Archive post
Home Assistant Users - View your Hive Witness stats at a glance with this dashboard card
• c0ff33a
Build a Home Assistant dashboard for Hive witness and account statistics, with REST sensor YAML, installation steps, customization and troubleshooting.
# Track Your Hive Witness in Home Assistant: Rank, Votes, Stake, Power Down & Portfolio Value


If you run a Hive witness and already use **Home Assistant** at home, you can add a dashboard card that keeps an eye on your witness and your wallet. No custom integrations, no HACS, and no API keys. It uses Home Assistant's built-in REST and template features, Hive's public API nodes, and CoinGecko for prices.
---
## What the card shows
**Witness**
- Witness rank (active witnesses only, so disabled witnesses are skipped)
- Total witness votes received (in MHP)
- Missed blocks
**Stake**
- Your own Hive Power, and your effective HP after delegations
- HP delegated out and delegated in
- How many witness votes you've cast
**Power down**
- Whether a power down is running
- Weekly payout and amount remaining
- Countdown to the next payout
**Wallet & portfolio**
- Liquid and savings HIVE and HBD
- Live HIVE and HBD prices
- Total portfolio value (liquid HIVE + savings + own HP + HBD; HP delegated *to* you isn't counted)
Prices are in **GBP (£)** by default. Changing currency is covered further down.
---
## How it works
There are two parts:
1. **A sensor package (`hive.yaml`).** This calls the Hive API (`condenser_api.get_accounts`, `get_dynamic_global_properties`, `get_witness_by_account` and `get_witnesses_by_vote`) and CoinGecko, then turns VESTS into HP for you.
2. **A dashboard card.** A plain Lovelace card that displays those sensors.
How often it updates:
- Account data: every 5 minutes
- Witness data: every 10 minutes
- Rank: every 15 minutes
- Prices: every 10 minutes
- The VESTS → HP ratio: hourly
---
## Step 1: Edit the sensor package
Copy the YAML below. Before saving it anywhere, **find and replace `YOUR_HIVE_ACCOUNT` with your account name**: lowercase, without the @. It appears **3 times**.
```yaml
###############################################################################
# HIVE BLOCKCHAIN PACKAGE for Home Assistant
#
# >>> FIND & REPLACE every "YOUR_HIVE_ACCOUNT" with your account name
# (lowercase, no @). It appears 3 times in this file.
# >>> Fiat currency is GBP. To change, replace "gbp" (3 places) and "£".
#
# Install: save as /config/packages/hive.yaml and make sure
# configuration.yaml contains:
#
# homeassistant:
# packages: !include_dir_named packages
#
# Then restart Home Assistant (a YAML reload is not enough for new REST sensors).
###############################################################################
rest:
# ---------------------------------------------------------------- Account
- resource: https://api.hive.blog
method: POST
headers:
Content-Type: application/json
payload: '{"jsonrpc":"2.0","method":"condenser_api.get_accounts","params":[["YOUR_HIVE_ACCOUNT"]],"id":1}'
scan_interval: 300
timeout: 20
sensor:
- name: Hive Liquid HIVE
unique_id: hive_liquid_hive
unit_of_measurement: HIVE
state_class: measurement
value_template: "{{ value_json.result[0].balance.split(' ')[0] | float(0) }}"
- name: Hive Savings HIVE
unique_id: hive_savings_hive
unit_of_measurement: HIVE
state_class: measurement
value_template: "{{ value_json.result[0].savings_balance.split(' ')[0] | float(0) }}"
- name: Hive Liquid HBD
unique_id: hive_liquid_hbd
unit_of_measurement: HBD
state_class: measurement
value_template: "{{ value_json.result[0].hbd_balance.split(' ')[0] | float(0) }}"
- name: Hive Savings HBD
unique_id: hive_savings_hbd
unit_of_measurement: HBD
state_class: measurement
value_template: "{{ value_json.result[0].savings_hbd_balance.split(' ')[0] | float(0) }}"
- name: Hive Vests Own
unique_id: hive_vests_own
unit_of_measurement: VESTS
value_template: "{{ value_json.result[0].vesting_shares.split(' ')[0] | float(0) }}"
- name: Hive Vests Delegated Out
unique_id: hive_vests_delegated_out
unit_of_measurement: VESTS
value_template: "{{ value_json.result[0].delegated_vesting_shares.split(' ')[0] | float(0) }}"
- name: Hive Vests Received
unique_id: hive_vests_received
unit_of_measurement: VESTS
value_template: "{{ value_json.result[0].received_vesting_shares.split(' ')[0] | float(0) }}"
- name: Hive Powerdown Rate Vests
unique_id: hive_powerdown_rate_vests
unit_of_measurement: VESTS
value_template: "{{ value_json.result[0].vesting_withdraw_rate.split(' ')[0] | float(0) }}"
- name: Hive Powerdown Remaining Vests
unique_id: hive_powerdown_remaining_vests
unit_of_measurement: VESTS
# to_withdraw / withdrawn are raw integers (VESTS x 1,000,000)
value_template: >
{% set a = value_json.result[0] %}
{{ ((a.to_withdraw | int(0)) - (a.withdrawn | int(0))) / 1000000 }}
- name: Hive Next Powerdown Raw
unique_id: hive_next_powerdown_raw
value_template: "{{ value_json.result[0].next_vesting_withdrawal }}"
- name: Hive Witness Votes Cast
unique_id: hive_witness_votes_cast
unit_of_measurement: votes
value_template: "{{ value_json.result[0].witness_votes | length }}"
- name: Hive Witness Proxy
unique_id: hive_witness_proxy
value_template: "{{ value_json.result[0].proxy if value_json.result[0].proxy else 'none' }}"
# ------------------------------------------------- Global props (VESTS -> HP)
- resource: https://api.hive.blog
method: POST
headers:
Content-Type: application/json
payload: '{"jsonrpc":"2.0","method":"condenser_api.get_dynamic_global_properties","params":[],"id":1}'
scan_interval: 3600
timeout: 20
sensor:
- name: Hive Per MVests
unique_id: hive_per_mvests
unit_of_measurement: HIVE
value_template: >
{% set fund = value_json.result.total_vesting_fund_hive.split(' ')[0] | float(0) %}
{% set shares = value_json.result.total_vesting_shares.split(' ')[0] | float(1) %}
{{ (fund / shares * 1000000) | round(6) }}
# ------------------------------------------------------- Witness details
- resource: https://api.hive.blog
method: POST
headers:
Content-Type: application/json
payload: '{"jsonrpc":"2.0","method":"condenser_api.get_witness_by_account","params":["YOUR_HIVE_ACCOUNT"],"id":1}'
scan_interval: 600
timeout: 20
sensor:
- name: Hive Witness Votes Vests
unique_id: hive_witness_votes_vests
unit_of_measurement: VESTS
# "votes" is raw VESTS x 1,000,000
value_template: "{{ (value_json.result.votes | int(0) / 1000000) if value_json.result else 0 }}"
json_attributes_path: "$.result"
json_attributes:
- total_missed
- last_confirmed_block_num
- running_version
- url
- signing_key
- name: Hive Witness Missed Blocks
unique_id: hive_witness_missed_blocks
unit_of_measurement: blocks
value_template: "{{ value_json.result.total_missed if value_json.result else 0 }}"
# ---------------------------------------- Witness rank (active witnesses only)
- resource: https://api.hive.blog
method: POST
headers:
Content-Type: application/json
payload: '{"jsonrpc":"2.0","method":"condenser_api.get_witnesses_by_vote","params":["",300],"id":1}'
scan_interval: 900
timeout: 30
sensor:
- name: Hive Witness Rank
unique_id: hive_witness_rank
# Disabled witnesses (null signing key) are skipped, so the rank matches
# the "active" rank shown on most Hive witness pages.
value_template: >
{% set ns = namespace(i=0, rank=0) %}
{% for w in value_json.result %}
{% if w.signing_key != 'STM1111111111111111111111111111111114T1Anm' %}
{% set ns.i = ns.i + 1 %}
{% if w.owner == 'YOUR_HIVE_ACCOUNT' %}{% set ns.rank = ns.i %}{% endif %}
{% endif %}
{% endfor %}
{{ ns.rank if ns.rank > 0 else '>' ~ ns.i }}
# ---------------------------------------------------------------- Prices
- resource: https://api.coingecko.com/api/v3/simple/price?ids=hive,hive_dollar&vs_currencies=gbp
scan_interval: 600
timeout: 20
sensor:
- name: Hive Price
unique_id: hive_price
unit_of_measurement: "£"
state_class: measurement
value_template: "{{ value_json.hive.gbp | float(0) }}"
- name: HBD Price
unique_id: hbd_price
unit_of_measurement: "£"
state_class: measurement
value_template: "{{ value_json.hive_dollar.gbp | float(0) }}"
template:
- sensor:
- name: Hive Power Own
unique_id: hive_power_own
unit_of_measurement: HP
state_class: measurement
state: >
{{ (states('sensor.hive_vests_own') | float(0)
* states('sensor.hive_per_mvests') | float(0) / 1000000) | round(3) }}
- name: Hive Power Effective
unique_id: hive_power_effective
unit_of_measurement: HP
state_class: measurement
state: >
{% set v = states('sensor.hive_vests_own') | float(0)
- states('sensor.hive_vests_delegated_out') | float(0)
+ states('sensor.hive_vests_received') | float(0) %}
{{ (v * states('sensor.hive_per_mvests') | float(0) / 1000000) | round(3) }}
- name: Hive Power Delegated Out
unique_id: hive_power_delegated_out
unit_of_measurement: HP
state: >
{{ (states('sensor.hive_vests_delegated_out') | float(0)
* states('sensor.hive_per_mvests') | float(0) / 1000000) | round(3) }}
- name: Hive Power Received
unique_id: hive_power_received
unit_of_measurement: HP
state: >
{{ (states('sensor.hive_vests_received') | float(0)
* states('sensor.hive_per_mvests') | float(0) / 1000000) | round(3) }}
- name: Hive Powerdown Weekly
unique_id: hive_powerdown_weekly
unit_of_measurement: HIVE
state: >
{{ (states('sensor.hive_powerdown_rate_vests') | float(0)
* states('sensor.hive_per_mvests') | float(0) / 1000000) | round(3) }}
- name: Hive Powerdown Remaining
unique_id: hive_powerdown_remaining
unit_of_measurement: HIVE
state: >
{{ (states('sensor.hive_powerdown_remaining_vests') | float(0)
* states('sensor.hive_per_mvests') | float(0) / 1000000) | round(3) }}
- name: Hive Powerdown Active
unique_id: hive_powerdown_active
state: "{{ 'Yes' if states('sensor.hive_powerdown_rate_vests') | float(0) > 0 else 'No' }}"
icon: mdi:arrow-down-bold-circle-outline
- name: Hive Next Powerdown
unique_id: hive_next_powerdown
device_class: timestamp
availability: >
{{ states('sensor.hive_next_powerdown_raw') not in ['unknown', 'unavailable', '']
and not states('sensor.hive_next_powerdown_raw').startswith('1969') }}
state: "{{ states('sensor.hive_next_powerdown_raw') ~ '+00:00' }}"
- name: Hive Witness Votes HP
unique_id: hive_witness_votes_hp
unit_of_measurement: HP
state_class: measurement
state: >
{{ (states('sensor.hive_witness_votes_vests') | float(0)
* states('sensor.hive_per_mvests') | float(0) / 1000000) | round(0) }}
- name: Hive Witness Votes MHP
unique_id: hive_witness_votes_mhp
unit_of_measurement: MHP
state: "{{ (states('sensor.hive_witness_votes_hp') | float(0) / 1000000) | round(2) }}"
- name: Hive Portfolio Value
unique_id: hive_portfolio_value
unit_of_measurement: "£"
device_class: monetary
state: >
{% set hive = states('sensor.hive_liquid_hive') | float(0)
+ states('sensor.hive_savings_hive') | float(0)
+ states('sensor.hive_power_own') | float(0) %}
{% set hbd = states('sensor.hive_liquid_hbd') | float(0)
+ states('sensor.hive_savings_hbd') | float(0) %}
{{ (hive * states('sensor.hive_price') | float(0)
+ hbd * states('sensor.hbd_price') | float(0)) | round(2) }}
```
---
## Step 2: Add the package to Home Assistant
How you do this depends on how Home Assistant is installed. If **Settings** has an **Add-ons** or **Apps** section, you're on **Home Assistant OS**: use Option A or B. If you see *"Apps require the Home Assistant Operating System"*, you're on **Docker/Container** or **Core**: use Option C.
### Option A: Home Assistant OS with the File editor app
1. Go to **Settings → Apps** (called **Add-ons** on older versions) and open the **store**. Search for **File editor**, then install and start it. Switch on **Show in sidebar**.
2. Open **File editor** from the sidebar. You'll be in the `/config` folder.
3. Click the **folder icon** (top left), then the **new folder icon**, and create a folder called `packages`.
4. Open `packages`, click the **new file icon** and name the file `hive.yaml`.
5. Paste in the YAML from Step 1, with your account name in it, and click **Save**.
6. Go back to `/config` and open `configuration.yaml` (see Step 3).
### Option B: Home Assistant OS with the Studio Code Server app
If you'd rather use a VS Code-style editor:
1. Go to **Settings → Apps → store**, then install and start **Studio Code Server**. Switch on **Show in sidebar**.
2. Open it from the sidebar. In the file explorer, right-click the root of `/config` → **New Folder** → `packages`.
3. Right-click `packages` → **New File** → `hive.yaml`. Paste in the YAML and save (**Ctrl+S**).
4. Open `configuration.yaml` from the explorer (see Step 3).
### Option C: Docker / Container (or Core) by hand
There are no apps on these installs, so you edit the files directly on the host.
**1. Find your config folder.** It's the host folder mapped to `/config` in the container, the one containing `configuration.yaml`. In `docker-compose.yml` it's the line that looks like `- /some/path:/config`. If you're not sure, run this on the host:
```
docker inspect homeassistant --format '{{ range .Mounts }}{{ .Source }} -> {{ .Destination }}{{ println }}{{ end }}'
```
The path on the left of `-> /config` is your folder. Change `homeassistant` if your container has a different name. On a **Core** install the folder is usually `~/.homeassistant`.
**2. Create the package file:**
```
cd /path/to/your/config
mkdir -p packages
nano packages/hive.yaml
```
Paste in the YAML. To save and exit, press **Ctrl+O**, **Enter**, then **Ctrl+X**.
**3. Open `configuration.yaml`:**
```
nano configuration.yaml
```
Then follow Step 3 below.
If your config folder is on a NAS or shared over the network, you can also do all of this in a normal desktop text editor.
---
## Step 3: Turn on packages in `configuration.yaml`
Add these two lines to `configuration.yaml`:
```yaml
homeassistant:
packages: !include_dir_named packages
```
⚠️ If there's **already** a `homeassistant:` line in the file, don't add a second one. Put the `packages:` line, indented, underneath the existing one.
---
## Step 4: Check and restart
1. Go to **Developer tools → YAML → Check configuration**. It should report the configuration as valid.
2. Do a **full restart**. A YAML reload won't load new REST sensors.
- HA OS: **Settings → System → ⋮ (top right) → Restart Home Assistant**
- Docker: `docker restart homeassistant`
Give it a minute or two for the sensors to fill in.
---
## Step 5: Add the dashboard card
1. Open your dashboard and click the **pencil icon** (top right) to edit.
2. Click **+ Add card**, scroll to the bottom and pick **Manual**.
3. **Delete everything already in the box**, paste the YAML below, then click **Save**.
```yaml
type: vertical-stack
cards:
- type: glance
title: HIVE Witness
columns: 3
entities:
- entity: sensor.hive_witness_rank
name: Rank
icon: mdi:podium
- entity: sensor.hive_witness_votes_mhp
name: Votes
icon: mdi:vote
- entity: sensor.hive_witness_missed_blocks
name: Missed
icon: mdi:cube-off-outline
- type: entities
entities:
- type: section
label: Stake
- entity: sensor.hive_power_own
name: Hive Power (own)
icon: mdi:lightning-bolt
- entity: sensor.hive_power_effective
name: Effective HP
icon: mdi:lightning-bolt-circle
- entity: sensor.hive_power_delegated_out
name: Delegated out
icon: mdi:arrow-right-bold
- entity: sensor.hive_power_received
name: Delegated in
icon: mdi:arrow-left-bold
- entity: sensor.hive_witness_votes_cast
name: Witness votes cast
icon: mdi:account-check
- type: section
label: Power Down
- entity: sensor.hive_powerdown_active
name: Powering down
- entity: sensor.hive_powerdown_weekly
name: Weekly payout
icon: mdi:calendar-week
- entity: sensor.hive_powerdown_remaining
name: Remaining
icon: mdi:progress-download
- entity: sensor.hive_next_powerdown
name: Next payout
format: relative
icon: mdi:clock-outline
- type: section
label: Wallet
- entity: sensor.hive_liquid_hive
name: HIVE (liquid)
icon: mdi:wallet
- entity: sensor.hive_savings_hive
name: HIVE (savings)
icon: mdi:piggy-bank
- entity: sensor.hive_liquid_hbd
name: HBD (liquid)
icon: mdi:currency-usd
- entity: sensor.hive_savings_hbd
name: HBD (savings)
icon: mdi:piggy-bank-outline
- entity: sensor.hive_price
name: HIVE price
icon: mdi:chart-line
- entity: sensor.hbd_price
name: HBD price
icon: mdi:chart-line-variant
- type: entity
entity: sensor.hive_portfolio_value
name: Portfolio Value
icon: mdi:cash-multiple
```
💡 **Getting a configuration error?** The Manual card starts with some placeholder text, often including a `type:` line. If you paste underneath it instead of replacing it, you end up with two `type:` lines and Home Assistant rejects the card. Clear the box completely first. If you still get an error, removing the `type: vertical-stack` line also fixes it.
---
## Customising
- **Currency:** in `hive.yaml`, replace `gbp` (3 places) with `usd`, `eur` and so on, and `£` with your symbol.
- **API node:** the package uses `api.hive.blog`. If that's slow for you, replace each `resource: https://api.hive.blog` with another node, such as `https://api.deathwing.me` or `https://api.openhive.network`. Or run it against your own node, since you're a witness 😉
- **Rank:** this counts active witnesses only. If you're outside the top 300, it shows something like `>290`.
- **Not a witness?** The card still works for any account. The witness rows just show 0.
## Troubleshooting
- **Sensors show "unavailable":** check **Settings → System → Logs** for errors mentioning `rest` or `hive`. The usual cause is a typo in the account name, or `YOUR_HIVE_ACCOUNT` left in one of the 3 places.
- **Entities not found on the card:** if you already had sensors with the same names, Home Assistant may have added `_2` to the new ones. Check **Settings → Devices & services → Entities**, search for "hive" and update the card to match.
---
## Ideas for next steps
- Add a **history graph** of witness votes or HIVE price.
- Create an **automation** to notify you when your rank changes or missed blocks go up.
Questions and improvements are welcome in the comments 👇