# Track Your Hive Witness in Home Assistant: Rank, Votes, Stake, Power Down & Portfolio Value ![Home Assistant Hive Stats Card](https://files.peakd.com/file/peakd-hive/c0ff33a/23swgEFtNgPrGSMikMg5TuMEcwbT4fxDvmHD2EKW1mGeNtLnJpxUqpFEz9QsVuyX9qqti.png) ![Home Assistant Hive Stats Card lower portion](https://files.peakd.com/file/peakd-hive/c0ff33a/23swg9rTWKojVs886y4QYFe9sGXFXBY8zdH1r5T7rNvacMPPNByev7CseJ3xtCFuBnDRV.png) 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 👇