How To: Ethereum Mining Dashboard. HiveOS, Ethermine pool, Crypto Prices and DB Historical data statistics

Hey everyone,
I recently got into ETH mining so as you might imagine, the next thing was to integrate everything into HA.

Besides monitoring my gains, It is really useful to integrate GPU data, hashrates and temperatures into HA, and use it to control the heating or get instant notifications when something goes wrong.

It turned out quite long, so i broke it into clickable parts:


1. Ethermine pool data

All ethermine pool integration was done by this wonderful little plugin from @thomasprior. He is actively developing it currently and it can be found here:
https://github.com/ThomasPrior/EthermineInfo
So after installing the plugin following the instructions on github you need to create a sensor like so:

sensor:
  - platform: ethermineinfo
    miner_address: !secret my_wallet_address
    currency_name: EUR

This creates a sensor that provides all the current data from Ethermine.

Now we need to create template sensors to display these things, here’s how i chose to do it:

  - platform: template
    sensors:
      eth_unpaid: 
        friendly_name: "Unpaid Eth Ethermine"
        value_template: "{{(states.sensor.ethermineinfo_eXXXX.attributes['unpaid'] /1000000000000000000 )}}"
        unit_of_measurement: "ETH"
      eth_current:
        friendly_name: "Current Hashrate Ethermine"
        value_template: "{{ (states.sensor.ethermineinfo_eXXXX.attributes['current_hashrate'] /1000000 )|round(2)}}"
        unit_of_measurement: "MH/s"
      eth_reported:
        friendly_name: "Reported Hashrate Ethermine"
        value_template: "{{ (states.sensor.ethermineinfo_eXXXX.attributes['reported_hashrate'] /1000000 )|round(2)}}"
        unit_of_measurement: "MH/s"
      eth_average:
        friendly_name: "Average Hashrate Ethermine 24h"
        value_template: "{{ (states.sensor.ethermineinfo_eXXXX.attributes['average_hashrate_24h'] /1000000 )|round(2)}}"
        unit_of_measurement: "MH/s"
      eth_valid:
        friendly_name: "Valid Shares Ethermine"
        value_template: "{{ (states.sensor.ethermineinfo_eXXXX.attributes['valid_shares'] )}}"
        unit_of_measurement: "Shares"
      eth_stale:
        friendly_name: "Stale Shares Ethermine"
        value_template: "{{ (states.sensor.ethermineinfo_eXXXX.attributes['stale_shares'] )}}"
        unit_of_measurement: "Shares"
      eth_invalid:
        friendly_name: "Invalid Shares Ethermine"
        value_template: "{{ (states.sensor.ethermineinfo_eXXXX.attributes['invalid_shares'] )}}"
        unit_of_measurement: "Shares"
      eth_success_ratio:
        friendly_name: "Success Rate Ethermine"
        value_template: "{{ 
          (((
          (states.sensor.ethermineinfo_eXXXX.attributes['valid_shares'])

          )
          /((states.sensor.ethermineinfo_eXXXX.attributes['valid_shares'])
          +(states.sensor.ethermineinfo_eXXXX.attributes['invalid_shares'])
          +(states.sensor.ethermineinfo_eXXXX.attributes['stale_shares'])
          ))|round(3)
          )*100
          }}"
        unit_of_measurement: "%"

@thomasprior has since added more features in v1.0.1 so you could use them accordingly


2. Online crypto prices

At the time I imported prices from another custom component installed through HACS called bitfetch
https://github.com/BitFetch/bitfetch-home-assistant

You need to add this to your configuration or your package file, after getting your api key as described above. Currency pairs are also available in the documentation:

Code
  - platform: bitfetch
    pair: ETHEUR
    api_key: **api_key**
    scan_interval: 600 #seconds
    
## Same for ETHUSD

[details=Code]I also made two time difference sensors to know when the currency rates last updated.

Code
sensor:
  - platform: template
    sensors:

      ethusd_time_since_last_update:
        friendly_name: "USD price updated"
        value_template: "{{((as_timestamp(now()) - as_timestamp(states.sensor.bitfetch_ethusd.attributes['last_updated']) )/60)|round(0)}}"
        unit_of_measurement: "Minutes"
        icon_template: mdi:timer

      etheur_time_since_last_update:
      ### same for bitfetch_etheur

Those are displayed in my UI with the help of secondaryinfo-entity-row HACS plugin

Code
type: entities
entities:
  - entity: sensor.bitfetch_etheur
    name: ETH EUR Price
    type: 'custom:secondaryinfo-entity-row'
    secondary_info: '[[ sensor.etheur_time_since_last_update ]] Minutes Ago'
## same for ethusd_time_since_last_update 

image


3. HiveOS mining rig information.
3.1 HiveOS config.

Now here is where i had to experiment a little but I’ve managed to get it to work steadily.

@jffz (I’m guessing is the same person) has a nice code over on github:
https://gist.github.com/jffz/dbcfed2792ab07749ddf0a3e6f5039ea

*Note: please be careful, there is a whitespace on the above code which needs to be removed if you paste it as is. The second value_template needs an edit. - Also note that I am a linux noob so do the next steps at your own risk

Now this did work great, but i noticed it randomly stopped working after a couple of days or did not restart on miner_restart. So here is how I ended up fixing it:

  • I’m assuming you have installed “Mosquitto Broker” add-on from supervisor, if not, follow the documentation and you should get there.
  • Create a username and password inside the configuration of mosquitto that will be dedicated to your mining machine
  • Copy the first part of the code from the github link above in your favorite code editor, enter your local broker address under BROKER, a unique topic, like “hive_os_mqtt_info” and fill in the username and password that you set on your HA mosquitto broker.
  • remove the -f flag after tail
    You should end up with something like this (set the TOPIC to whatever you want):
#!/bin/bash
# MQTT settings
BROKER="HA IP"
TOPIC="hive_mqtt_1"
USER="hive_os_mqtt_user"
PASS="password"

# Ensure mosquitto-clients is installed
dpkg -s mosquitto-clients >/dev/null 2>&1 || apt update && apt install -y mosquitto-clients

# Stream logs to MQTT
tail /var/log/hive-agent.log | while read -r line; do
    json_line=$(echo ${line} | awk -F'[<>]' {'print $2'})
    if $(echo "$json_line" | jq -e 'has("method")'); then
        mosquitto_pub -h $BROKER -t $TOPIC -u "$USER" -P "$PASS" -m "$json_line"
    fi
done
  • Now copy the whole code block.

  • In the HiveOS farm UI, click on your local IP address.
    image

  • This should open a ssh window to your machine (shellinabox)

  • Initial username is user and pw is 1

  • There is a command in the initial help lines that lets you change your pwd for ssh and vnc, i suggest you do so

  • Enter sudo nano and press enter, to open a new text editor.

  • Right click on the background and select “paste from browser” (or similar)_ from the context menu

  • Paste your whole thing in the box and click ok.

  • press CRTL+O to save, type in a filename with a .sh extension (like hiveos2mqtt.sh)

  • press enter and then CRTL X to exit.

  • If you have not changed directory, you should be in /home/user. You can confirm this by entering pwd and pressing enter.

  • While there run chmod +x /home/user/hiveos2mqtt.sh (I think this step is needed but I might be mistaken). If it gives you any trouble try sudo chmod +x /home/user/hiveos2mqtt.sh

  • That’s almost it, now the script should run once whenever you type in hiveos2mqtt.sh. It gets the last log output, converts it into json and broadcasts it to your mqtt server.

  • You need an mqtt browser to check this out, but one way to quickly check if its working would be to refresh the logs of mosquitto broker. You should see at least one line like this:

1621955581: New client connected from 10.0.0.110 as mosqpub|30600-rig1 (p1, c1, k60, u'hive_os_1').
1621955581: Client mosqpub|30600-rig1 disconnected.
1621955581: New connection from 10.0.0.110 on port 1883.
  • Now we need to make the script run once every minute, and this is the most stable way i could figure out.

  • Run sudo nano /hive/etc/crontab.root

  • Go to the end of the file and add this line: * * * * * /home/user/hiveos2mqtt.sh exactly as it is, with the asterisks. Also hit the return key after this command to start a new line.

  • It should look like this:

  • Hit CRTL+O to save changes, YES, then CRTL+X to exit.

  • Reboot with reboot or through your UI
    image

  • That was it from linux side. Now once you reboot, the HiveOS machine will send data to your HA once a minute.

  • Crontab job might need to be re-entered after a hiveOS update.

3.2 HA config.
  • From HA’s side, we need to intercept these data with the two sensors that are mentioned above.
  • So go to your ha config files and add the following block of code under a sensor: tag
sensor:
  - platform: mqtt
    name: hiveos_stats
    state_topic: "hive_mqtt_1"
    value_template: "{{ value_json.params.miner_stats.uptime }}"
    json_attributes_topic: "hive_mqtt_1"
    json_attributes_template: "{{ value_json.params.miner_stats | to_json }}"

  - platform: mqtt
    name: hiveos_params
    state_topic: "hive_mqtt_1"
    value_template: "{{ value_json.params.miner_stats.uptime }}"
    json_attributes_topic: "hive_mqtt_1"
    json_attributes_template: "{{ value_json.params | to_json }}"
  • Restart HA

  • Go to Developer Tools → States tab and search for “hiveos”
    You should see something like this:

  • Then you need to create a template sensor for each of the values that you are interested in. You can troubleshoot in the template tab to try different stuff. Here are mines:

  - platform: template
    sensors:

      hiveos_uptime:
        friendly_name: "Hive OS Uptime"
        value_template: >-
          {% set time = (states.sensor.hiveos_stats.attributes['uptime'] | int) | int %}
          {% set minutes = ((time % 3600) / 60) | int %}
          {% set hours = ((time % 86400) / 3600) | int %}
          {% set days = (time / 86400) | int %}
          
          {%- if time < 60 -%}
            Less than a minute
          {%- else -%}
            {%- if days > 0 -%}
              {{ days }}d
            {%- endif -%}
            {%- if hours > 0 -%}
              {%- if days > 0 -%}
                {{ ' ' }}
              {%- endif -%}
              {{ hours }}h
            {%- endif -%}
            {%- if minutes > 0 -%}
              {%- if days > 0 or hours > 0 -%}
                {{ ' ' }}
              {%- endif -%}
              {{ minutes }}m
            {%- endif -%}
          {%- endif -%}
    # value_template: "{{ (states.sensor.hiveos_stats.attributes['uptime']) }}" 
    # unit_of_measurement: "s"

      hiveos_cpu_temp:
        friendly_name: "Hive OS CPU Temp"
        value_template: "{{ (states.sensor.hiveos_params.attributes['cputemp'][0]) }}"
        unit_of_measurement: "°C"

      hiveos_total_mhs:
        friendly_name: "Hive OS Total MH/s"
        value_template: "{{ (states.sensor.hiveos_params.attributes['total_khs'])/1000 }}"
        unit_of_measurement: "MH/s"

      hiveos_total_pwr:
        friendly_name: "Hive OS Cards NET Power Consumption"
        value_template: "{{(states.sensor.gpu_0_pwr.state)|int+(states.sensor.gpu_1_pwr.state)|int+(states.sensor.gpu_2_pwr.state)|int+(states.sensor.gpu_3_pwr.state)|int+(states.sensor.gpu_4_pwr.state)|int+(states.sensor.gpu_5_pwr.state)|int+(states.sensor.gpu_6_pwr.state)|int}}"
        unit_of_measurement: "W"

### gpu0
      gpu_0_index:
        value_template: '0'
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Index"
      gpu_0_name:
        value_template: "1660S-ASUS1"
      gpu_0_hash:
        value_template: "{{ (states.sensor.hiveos_stats.attributes['hs'][states.sensor.gpu_0_index.state|int])/1000 }}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Hash"
        unit_of_measurement: "MH/s"
      gpu_0_core:
        value_template: "{{ (states.sensor.hiveos_params.attributes['temp'][states.sensor.gpu_0_index.state|int +1]) }}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Core Temp"
        unit_of_measurement: "°C"
      gpu_0_fan:
        value_template: "{{ (states.sensor.hiveos_params.attributes['fan'][states.sensor.gpu_0_index.state|int +1]) }}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Fan Speed"
        unit_of_measurement: "RPM"
      gpu_0_pwr:
        value_template: "{{ (states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) }}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Power Consumption"
        unit_of_measurement: "W"

#Mhs/Watt
      gpu_0_pwr_eff:
        value_template: "{{ (((states.sensor.hiveos_stats.attributes['hs'][states.sensor.gpu_0_index.state|int])/1000 )/(states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) )|round(3)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Power Efficiency"
        unit_of_measurement: "Mh/W"

#Cost, Net and Gross Earnings per GPU
      gpu_0_cost_per_month:
        value_template: "{{ ((states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) * (states.sensor.calculated_power_to_price_multiplier.state|float))|round(2)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Cost Per Month"
        unit_of_measurement: "€"
      gpu_0_euro_per_month:
        value_template: "{{((states.sensor.gpu_0_hash.state |float/ states.sensor.hiveos_total_mhs.state |float)* states.sensor.eur_per_30d.state|float)|round(2)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} EUR Per Month"
        unit_of_measurement: "€"
      gpu_0_net_euro_per_month:
        value_template: "{{(((states.sensor.gpu_0_hash.state |float/ states.sensor.hiveos_total_mhs.state |float)* states.sensor.eur_per_30d.state|float) -states.sensor.gpu_0_cost_per_month.state|float)|round(2)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Net EUR Per Month"
        unit_of_measurement: "€"

### gpu...
...

I created one set of sensors for each GPU.
I also added some average sensors through this great HACS integration
https://github.com/Limych/ha-average

  - platform: average
    name: "HiveOS GPU AVG Temp"
    entities:
      - sensor.gpu_0_core
      - sensor.gpu_1_core 
      #.. add all the gpus.
      

  - platform: average
    name: 'HiveOS Temp AVG24h - GPU0 1660S1'
    duration:
      days: 1
    entities:
      - sensor.gpu_0_core

... same for the rest of the gpus

4. History data from my local database

Since i dont know much about Ethereum and its mining process, I wanted to create my own indicators on my expected outcome, based on the production of the last 1h, 6h, 12h and 24h.

4.1 Total eth Mined sensor

To do this, I created an ethereum counter that only sums the amounts I have mined.
This is current unpaid ethereum plus every payout that was done from my pool to my wallet.

      eth_mined_total:
        friendly_name: "Total ETH Mined"
        value_template: "{{(states.sensor.ethermineinfo_eXXXX.attributes['unpaid'] /1000000000000000000 ) + 0.xxxxxxx + 0.xxxxxx }}"
                                  #### Current in pool ......................................................1st payout....2nd payout...
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum

Unfortunately I have not found a better way to calculate this automatically, so once a week I need to update the new number that was paid out.

I don’t want to use my wallet amount in case I do some transaction at some point

History Sensors

Now to get the value of the above sensor from 1,6,12 and 24 h before.

sensor:
  - platform: sql
    db_url: !secret hassioslave_db_link  ###can be omitted if using default recorder settings
    queries:
      - name: eth_mined_total_history_1h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_mined_total' AND created < DATE_ADD(NOW(), INTERVAL -3-1 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"
      - name: eth_mined_total_history_6h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_mined_total' AND created < DATE_ADD(NOW(), INTERVAL -3-6 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"
      - name: eth_mined_total_history_12h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_mined_total' AND created < DATE_ADD(NOW(), INTERVAL -3-12 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"
      - name: eth_mined_total_history_24h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_mined_total' AND created < DATE_ADD(NOW(), INTERVAL -3-24 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"

See here for more info on how these sensors work.

History Calculations

Now I wanted to get an estimate for eth production per hour/day/week based on the production of the last 1,6,12 and 24h so a total of (3x4) 12 sensors:

  - platform: template
    sensors:
      eth_per_hour_1h_sample:
        friendly_name: "Eth per Hour (1h Sampled)"
        value_template: "{{((states.sensor.eth_mined_total.state) |float - (states.sensor.eth_mined_total_history_1h.state) |float ) |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_day_1h_sample:
        friendly_name: "Eth per Day (1h Sampled)"
        value_template: "{{ ((((states.sensor.eth_mined_total.state) |float - (states.sensor.eth_mined_total_history_1h.state) |float) |float )*24 ) |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_30d_1h_sample:
        friendly_name: "Eth per 30d (1h Sampled)"
        value_template: "{{ ((((states.sensor.eth_mined_total.state) |float - (states.sensor.eth_mined_total_history_1h.state) |float) |float )*24*30 ) |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum

      eth_per_hour_6h_sample:
        friendly_name: "Eth per Hour (6h Sampled)"
        value_template: "{{(((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_6h.state) |float)/6 ) |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_day_6h_sample:
        friendly_name: "Eth per Day (6h Sampled)"
        value_template: "{{ (((((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_6h.state) |float)/6 ) |float )*24)  |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_30d_6h_sample:
        friendly_name: "Eth per 30d (6h Sampled)"
        value_template: "{{ (((((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_6h.state) |float)/6) |float )*24*30) |round(10)  }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum

      eth_per_hour_12h_sample:
        friendly_name: "Eth per Hour (12h Sampled)"
        value_template: "{{(((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_12h.state) |float)/12 ) |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_day_12h_sample:
        friendly_name: "Eth per Day (12h Sampled)"
        value_template: "{{ (((((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_12h.state) |float)/12) |float )*24)  |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_30d_12h_sample:
        friendly_name: "Eth per 30d (12h Sampled)"
        value_template: "{{ (((((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_12h.state) |float)/12) |float )*24*30 ) |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum

      eth_per_hour_24h_sample:
        friendly_name: "Eth per Hour (24h Sampled)"
        value_template: "{{(((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_24h.state) |float)/24) |round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_day_24h_sample:
        friendly_name: "Eth per Day (24h Sampled)"
        value_template: "{{ (((((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_24h.state) |float)/24 ) |float )*24)|round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_30d_24h_sample:
        friendly_name: "Eth per 30d (24h Sampled)"
        value_template: "{{ (((((states.sensor.eth_mined_total.state) |float -  (states.sensor.eth_mined_total_history_24h.state) |float)/24 ) |float )*24*30)|round(10) }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum

*This code can have a lot of refactoring but it’s on the to-do list

End Result


5. Other Calculations & Sensors
5.1 Total hours since start of mining based production estimates

So, as i said I’m new to this so I also wanted an overall calculation of my mining rig’s production.
I created a template sensor that calculates the hours since I started mining.
This lets me see my actual true eth production per hour, day and month.

sensor:
  - platform: template
    sensors:
      hours_since_start_mining:
        friendly_name: "Total Hours Mining"
        value_template: "{{((as_timestamp(now()) - as_timestamp('2021-5-11 22:30:00') ) | int /3600)|round(2)}}"
        unit_of_measurement: "hours"

      eth_per_hour:
        friendly_name: "Total Eth per Hour"
        value_template: "{{(states.sensor.eth_mined_total.state) |float / (states.sensor.hours_since_start_mining.state)|float }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_day:
        friendly_name: "Total Eth per Day"
        value_template: "{{ ((states.sensor.eth_per_hour.state) |float )*24 }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum
      eth_per_30d:
        friendly_name: "Total Eth per 30d"
        value_template: "{{ ((states.sensor.eth_per_day.state) |float )*30 }}"
        unit_of_measurement: "ETH"
        icon_template: mdi:ethereum

image

5.2 Wallet Monitoring

I also had to monitor my wallet, this is done with this HA sensor:

  - platform: etherscan
    address: "0x...wallet_address"
5.3 Room conditions & true power consumption

Those are measured with the help of Zigbee, a xiaomi temp/hum sensor and power plug with power consumption. (which has also proven useful when i had to remotely hard reboot the rig)
image
image
image
The little lock there prevents me from accidentally turning the whole thing off.
Here’s the code

5.4 Power Efficiency for each card (Mhs/Watt)

Added these sensors for each card:

      gpu_0_pwr_eff:
        value_template: "{{ (((states.sensor.hiveos_stats.attributes['hs'][states.sensor.gpu_0_index.state|int])/1000 )/(states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) )|round(3)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Power Efficiency"
        unit_of_measurement: "Mh/W"

Now, with the help of auto-entities I can create an automatic lovelace card that sorts my gpus per their efficiency:
image
Lovelace Code:

card:
  show_header_toggle: false
  title: Card PWR eff
  type: entities
filter:
  include:
    - entity_id: sensor.*pwr_eff*
sort:
  method: state
  numeric: true
  reverse: true
type: 'custom:auto-entities'
5.5 Electricity Cost, Gross and Net earnings, in total and per GPU

I calculated an estimate of my monthly cost of unit of electricity and created a multiplier.

  • Created total montly cost estimate depending on current wall consumption.
  • Substracted Wall consumption minus total Cards consumption to get the power and cost of the motherboard plus power losses of the PSU
  • Calculated a NET eur per month by substracting Total earnings minus Total electricity Cost.
        #################COST CALCULATIONS
      calculated_power_to_price_multiplier:
        friendly_name: "Cost per Wh per Month"
        value_template: "{{116.1775099/1000}}"
        unit_of_measurement: "€"

      est_cost_per_month:
        friendly_name: "Total Cost per Month"
        value_template: "{{(states.sensor.dn_bm_main_room_xiaomi_plug_consumption.state|int * states.sensor.calculated_power_to_price_multiplier.state |float)|round(2)}}"
        unit_of_measurement: "€"
      
      rig_base_power:
        friendly_name: "Rig Base Power"
        value_template: "{{states.sensor.dn_bm_main_room_xiaomi_plug_consumption.state|int - states.sensor.hiveos_total_pwr.state |int}}"
        unit_of_measurement: "W"

      est_rig_cost_per_month:
        friendly_name: "Rig Base Cost per Month"
        value_template: "{{(states.sensor.rig_base_power.state|int * states.sensor.calculated_power_to_price_multiplier.state |float)|round(2)}}"
        unit_of_measurement: "€"

      net_eur_per_month:
        friendly_name: "Net EUR per Month"
        value_template: "{{states.sensor.eur_per_30d.state|int - states.sensor.est_cost_per_month.state |int}}"
        unit_of_measurement: "€"

After calculating the calculated_power_to_price_multiplier I can create the following sensors for each card based on their Mh/s participation and their power consumption:

      gpu_0_cost_per_month:
        value_template: "{{ ((states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) * (states.sensor.calculated_power_to_price_multiplier.state|float))|round(2)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Cost Per Month"
        unit_of_measurement: "€"
      gpu_0_euro_per_month:
        value_template: "{{((states.sensor.gpu_0_hash.state |float/ states.sensor.hiveos_total_mhs.state |float)* states.sensor.eur_per_30d.state|float)|round(2)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} EUR Per Month"
        unit_of_measurement: "€"
      gpu_0_net_euro_per_month:
        value_template: "{{(((states.sensor.gpu_0_hash.state |float/ states.sensor.hiveos_total_mhs.state |float)* states.sensor.eur_per_30d.state|float) -states.sensor.gpu_0_cost_per_month.state|float)|round(2)}}"
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Net EUR Per Month"
        unit_of_measurement: "€"

I have created separate cards to present the data, but it is better presented in a summary table as described below in 5.6

5.6 Summary Table card

The only Table thingy i could find for lovelace was this (flex-table-card).
To make this work, each gpu needs to be presented as its own entity with its own attributes (at least this is how i made it work).
So i created a template entity (documentation) for each gpu, where i added attributes for the sensors i needed.

template:
  - sensor:
      - name: unified_gpu_0
        state: "{{states('sensor.gpu_0_name')}}"
        attributes:
          index: '0'
          hash: "{{ (states.sensor.hiveos_stats.attributes['hs'][states.sensor.gpu_0_index.state|int])/1000 }}"
          core: "{{ (states.sensor.hiveos_params.attributes['temp'][states.sensor.gpu_0_index.state|int +1]) }}"
          fan: "{{ (states.sensor.hiveos_params.attributes['fan'][states.sensor.gpu_0_index.state|int +1]) }}"
          pwr: "{{ (states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) }}"
          pwr_eff: "{{ (((states.sensor.hiveos_stats.attributes['hs'][states.sensor.gpu_0_index.state|int])/1000 )/(states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) )|round(3)}}"
          cost_per_month:  "{{ ((states.sensor.hiveos_params.attributes['power'][states.sensor.gpu_0_index.state|int +1]) * (states.sensor.calculated_power_to_price_multiplier.state|float))|round(2)}}"
          euro_per_month: "{{((states.sensor.gpu_0_hash.state |float/ states.sensor.hiveos_total_mhs.state |float)* states.sensor.eur_per_30d.state|float)|round(2)}}"
          net_euro_per_month: "{{(((states.sensor.gpu_0_hash.state |float/ states.sensor.hiveos_total_mhs.state |float)* states.sensor.eur_per_30d.state|float) -states.sensor.gpu_0_cost_per_month.state|float)|round(2)}}"

#same for the rest of the gpus

This needs to be called directly in your configuration.yaml, or in a separate file by adding template: !include template.yaml in your configuration (and ommiting the leading template: from the file).
I couldn’t get it to work from a package.

Then the Lovelace card code:

type: 'custom:flex-table-card'
title: GPU INFO
entities:
  include: sensor.unified_gpu_*
sorty_by: index+
strict: true
clickable: true
columns:
  - data: state
    name: Name
  - data: index
    name: Index
  - data: hash
    name: Hashrate
    suffix: ' Mh/s'
  - data: core
    name: Core Temp
    suffix: ' C'
  - data: fan
    name: Fan %
    suffix: ' %'
  - data: pwr
    name: PWR
    suffix: ' W'
  - data: pwr_eff
    name: EFF
    suffix: ' Mh/W'
  - data: euro_per_month
    name: €/mo
    suffix: ' €'
  - data: cost_per_month
    name: Cost/mo
    suffix: ' €'
  - data: net_euro_per_month
    name: Net €/mo
    suffix: ' €'

And the end result:
image


Anyway, this is getting a little long…

Meanwhile, here’s an overview of my dashboard.


PS. I am not an experienced coder, so suggestions and corrections are more than welcome.

I hope I masked all sensitive stuff correctly :smiley:


Significant edits:

  • Modified HA MQTT sensors to correctly update on uptime change.
    value_json.params.uptime to value_json.params.miner_stats.uptime on both sensors
  • Changed Bitfetch sensors to update every 10 minutes in order to say within the free monthly limit.
    scan_interval: 300 #secondsscan_interval: 600 #seconds
  • Added a power efficiency sensor for each card to be able to sort per Mhs/Watt
    Details in section 5.4
  • Added Montly (30d) cost per gpu, Gross earnings per gpu and Net earnings per gpu (Section 5.5)
  • Added a summary table with all data at a glance (Section 5.6)
  • Changed the mqtt topic in the code sample to match HA topic as suggested by @Emu05
13 Likes

@krash Where do you insert mqtt port?

I’m receiving “Connection refused”

1883 is the default, you can change it in the configuration page of the mosquitto addon in HA.

Also check the mosquitto log tab in HA, it’s also in the addon settings, there’s a log tab.

My default port was not 1883. Not it’s working. Thanks.

Have you used nodered to parse json? Or do you have create a sensor and parse in configuration?

I created the sensors with yaml, exactly as described above.

@krash hiveos Do you have de sensor.hiveos_stats, like this? Or do you have split sensors?

I did this, to split the sensors for each of my cards, so i can also keep history data.
I have added some extra sensors since then, i will update OP at some point

1 Like

It works perfectly, thanks!

@krash Have you created the oiwer efficiency sensor based on HiveOs? I’m trying to add it too, with no success

      gpu_0_ef:
        friendly_name_template: "{{states.sensor.gpu_0_name.state}} Efficiency"
        value_template: '{{ ((states.sensor.gpu_0_hash.state|float)/(states.sensor.gpu_0_pwr.state|float))|round(3) }}'
        unit_of_measurement: "MHs/W"

Yep, they work ok for me.
You are basically dividing hashrate by power consumption.
Have you created those two sensors beforehand?
gpu_0_hash and gpu_0_pwr

I got it working THANK YOU! … How do you setup more than one rig? I think the only issue that is stopping me is the sensor setup but I’m not able to figure it out.

Hey, glad it helped.
For a second rig, you will need a second mqtt username /pw set up in your mosquitto, then just add new mqtt sensors with different names like hiveos_2_...
At least I think so :stuck_out_tongue:

I setup another username and password, that’s working fine. I can get the different sensors to show up in developer mode.
If I leave json_attributes_topic: “hive_mqtt_1” set for all for sensors it displays the stats from the first rig on all four sensors. If I change the json attributes topic for sensor three and four the state is unknown. Not sure what to do.

sensor:

  • platform: mqtt
    name: hiveos_stats
    state_topic: “hive_mqtt_1”
    value_template: “{{ value_json.params.miner_stats.uptime }}”
    json_attributes_topic: “hive_mqtt_1”
    json_attributes_template: “{{ value_json.params.miner_stats | to_json }}”

  • platform: mqtt
    name: hiveos_params
    state_topic: “hive_mqtt_1”
    value_template: “{{ value_json.params.miner_stats.uptime }}”
    json_attributes_topic: “hive_mqtt_1”
    json_attributes_template: “{{ value_json.params | to_json }}”

  • platform: mqtt
    name: hiveos_stats_MINER3
    state_topic: “hive_mqtt_2”
    value_template: “{{ value_json.params.miner_stats.uptime }}”
    json_attributes_topic: “hive_mqtt_2”
    json_attributes_template: “{{ value_json.params.miner_stats | to_json }}”

  • platform: mqtt
    name: hiveos_params_MINER3
    state_topic: “hive_mqtt_2”
    value_template: “{{ value_json.params.miner_stats.uptime }}”
    json_attributes_topic: “hive_mqtt_2”
    json_attributes_template: “{{ value_json.params | to_json }}”

First off, please format your code correctly (by using this character: ` before and after) so we can help you out faster

so the first block code works ok,

  - platform: mqtt
    name: hiveos_stats
    state_topic: "hive_mqtt_1"
    value_template: "{{ value_json.params.miner_stats.uptime }}"
    json_attributes_topic: "hive_mqtt_1"
    json_attributes_template: "{{ value_json.params.miner_stats | to_json }}"

  - platform: mqtt
    name: hiveos_params
    state_topic: "hive_mqtt_1"
    value_template: "{{ value_json.params.miner_stats.uptime }}"
    json_attributes_topic: "hive_mqtt_1"
    json_attributes_template: "{{ value_json.params | to_json }}"

and this doesnt? :

platform: mqtt
name: hiveos_stats_MINER3
state_topic: “hive_mqtt_2”
value_template: “{{ value_json.params.miner_stats.uptime }}”
json_attributes_topic: “hive_mqtt_2”
json_attributes_template: “{{ value_json.params.miner_stats | to_json }}”

platform: mqtt
name: hiveos_params_MINER3
state_topic: “hive_mqtt_2”
value_template: “{{ value_json.params.miner_stats.uptime }}”
json_attributes_topic: “hive_mqtt_2”
json_attributes_template: “{{ value_json.params | to_json }}”
  • check that your home assistant syntax is right
  • check that you have the correct topic set on your second rig TOPIC="hive_mqtt_2" in the equivalent hiveos2mqtt.sh script.
  • check the mosquitto logs in HA supervisor that your 2nd rig actually connects and sends data
  • try another MQTT client to see all the traffic (download one, create a new user/pw in HA, connect with it, subscribe to all topics (#) and see what’s going on)
  • If all these are working, go back and check the HA sensors syntax.

That’s all i can think of right now.
Let me know if it’s helpful

Hi there. Is there any way to pull the history from Home Assistant to calculate and store total ETH mined in the last 24 hours?

Check part 4 in OP.

Isn’t this what you want?

sensor:
  - platform: sql
    db_url: !secret hassioslave_db_link  ###can be omitted if using default recorder settings
    queries:
#....
      - name: eth_mined_total_history_24h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_mined_total' AND created < DATE_ADD(NOW(), INTERVAL -3-24 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"

I saw that but I don’t have a separate database that holds the history from Home Assistant. I’m sorry if that doesn’t make sense. New to this! Would I need to set up a separate database to push the information to?

No, i think you can do it with the default database, by removing this line:

db_url: !secret hassioslave_db_link ###can be omitted if using default recorder settings

So it should be somewhat like this:

sensor:
  - platform: sql
    queries:
    ...

I have not tested it, but it should work according to the documentation.
Give it a try and let us know.

Hi @krash, that didn’t seem to work. I did as you stated and removed the db_url completely but I get unknown for the total history.

Note: I’m using the unpaid sensor because I haven’t cashed out yet.

 - platform: sql
    queries:
      - name: eth_mined_total_history_1h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_unpaid' AND created < DATE_ADD(NOW(), INTERVAL -3-1 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"
      - name: eth_mined_total_history_6h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_unpaid' AND created < DATE_ADD(NOW(), INTERVAL -3-6 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"
      - name: eth_mined_total_history_12h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_unpaid' AND created < DATE_ADD(NOW(), INTERVAL -3-12 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"
      - name: eth_mined_total_history_24h
        query: SELECT * FROM states WHERE entity_id = 'sensor.eth_unpaid' AND created < DATE_ADD(NOW(), INTERVAL -3-24 HOUR) ORDER BY state_id DESC LIMIT 1;
        column: 'state'
        unit_of_measurement: "ETH"

@krash How do you solve hiveos2mqtt.sh, that stops sending information after some time?