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
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 aftertail
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.
-
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 enteringpwd
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 trysudo 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
-
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
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
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)
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:
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:
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
Significant edits:
- Modified HA MQTT sensors to correctly update on uptime change.
value_json.params.uptime
tovalue_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 #seconds
→scan_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