I've been working with Observability and the Grafana stack lately, and while having a re-organise got thinking about surveying and harvesting information about our home network.
Home network is a dynamic environment - devices come and go, are forgotten. I had observed that Home Assistant (HASS) was quite good at "discovering" new devices on the network, and got thinking about how I could utilise this myself.
Information recorded manually gets outdated and unreliable fast, while information retrieved by surveying gives you a current view but can lack historic context. The trick is combining what's discovered with knowledge you'd like to preserve; discovery can give you "a device is connected, named X and has details Y", while preserving knowledge can tell you who it belonged to or why it was introduced.
First question was, how to find hosts HASS sees. HASS has an API! Let's explore - we will need:
HASS_URL
The URL of your Home Assistant instanceHASS_TOKEN
A long lived token from Home Assistant
Let's see what the states are in HASS.
curl -X GET -H "Authorization: Bearer ${HASS_TOKEN}" \
-H "Content-Type: application/json" \
${HASS_URL}/api/states
I get a response like:
[
{
"entity_id": "person.chris_burgess",
"state": "home",
"attributes": {
"editable": true,
"id": "chris_burgess",
"device_trackers": [
"device_tracker.chris_oneplus",
"device_tracker.chriss_ipad_2",
"device_tracker.nexus_5x",
"device_tracker.cph2529"
],
"latitude": -45.00,
"longitude": 170.00,
"gps_accuracy": 10,
"source": "device_tracker.abcdef1",
"user_id": "aabbccdd",
"friendly_name": "Chris Burgess"
},
"last_changed": "2025-04-21T19:11:33.996324+00:00",
"last_reported": "2025-04-21T22:36:42.920973+00:00",
"last_updated": "2025-04-21T22:36:42.920973+00:00",
"context": {
"id": "01234",
"parent_id": null,
"user_id": null
}
},
{
"entity_id": "device_tracker.ubuntu_server_2",
"state": "home",
"attributes": {
"source_type": "router",
"ip": "10.0.0.2",
"mac": "AB:CD:11:22:33:44",
"host_name": "ahem",
"last_time_reachable": "2025-04-21T22:43:16+00:00",
"connected_to": "fritz.box",
"connection_type": "LAN",
"icon": "mdi:lan-connect",
"friendly_name": "ahem"
},
"last_changed": "2025-04-21T19:12:32.411093+00:00",
"last_reported": "2025-04-21T22:43:18.691542+00:00",
"last_updated": "2025-04-21T22:43:18.691542+00:00",
"context": {
"id": "01234",
"parent_id": null,
"user_id": null
}
},
{
"entity_id": "device_tracker.the_nas",
"state": "home",
"attributes": {
"source_type": "router",
"ip": "10.0.0.3",
"mac": "AB:CD:11:22:33:44",
"host_name": "the-nas",
"last_time_reachable": "2025-04-21T22:43:16+00:00",
"connected_to": "fritz.box",
"connection_type": "LAN",
"icon": "mdi:lan-connect",
"friendly_name": "nas"
},
"last_changed": "2025-04-21T19:12:32.429386+00:00",
"last_reported": "2025-04-21T22:43:18.692900+00:00",
"last_updated": "2025-04-21T22:43:18.692900+00:00",
"context": {
"id": "01234",
"parent_id": null,
"user_id": null
}
},
// ...
]
Let's filter that down to hosts we're interested in:
curl -X GET -H "Authorization: Bearer ${HASS_TOKEN}" -H "Content-Type: application/json" ${HASS_URL}/api/states | jq '.[] | select(.state == "home" and .attributes.host_name != null) | {entity_id, state, host_name: .attributes.host_name}'
How about as a Markdown list:
curl -X GET -H "Authorization: Bearer ${HASS_TOKEN}" -H "Content-Type: application/json" ${HASS_URL}/api/states | jq -r '.[] | select(.state == "home" and .attributes.host_name != null) | "- \(.attributes.host_name) (\(.attributes.ip))"' | sort
Or as a table:
echo "| friendly name | host name | ip | notes |"
echo "|--|--|--|--|"
curl -X GET \
-H "Authorization: Bearer ${HASS_TOKEN}" \
-H "Content-Type: application/json" \
${HASS_URL}/api/states | jq -r '.[] | select(.state == "home" and .attributes.host_name != null) | "| \(.attributes.friendly_name) | `\(.attributes.host_name)` | `\(.attributes.ip)` | |"'
The output of the last might look like (after comments added):
friendly name | host name | ip | notes |
---|---|---|---|
9b7eb8b9-dff1-d401-5507-09a8aaaea195 | 9b7eb8b9-dff1-d401-5507-09a8aaaea195 |
10.0.0.59 |
? |
a1f6389c-bb13-c10f-3af0-cd147e51a662 | a1f6389c-bb13-c10f-3af0-cd147e51a662 |
10.0.0.52 |
? |
aooga | aooga |
10.0.0.101 |
VM running some services |
baluga | baluga |
10.0.0.102 |
|
Android-2 | Android-2 |
10.0.0.51 |
Visitor phone |
laptop-1 | work-laptop |
10.0.0.54 |
Work laptop |
Chromecast-Audio | Chromecast-Audio |
10.0.0.59 |
Best device |
Chromecast | Chromecast |
10.0.0.103 |
|
NAS-1 | NAS device |
10.0.0.53 |
|
DSP-W123 | DSP-W118 |
10.0.0.104 |
|
ESP-ABCDE1 | ESP-ABCDE1 |
10.0.0.55 |
|
ESP-123ABC | ESP-123ABC |
10.0.0.56 |
|
ESP-DEF432 | ESP-DEF432 |
10.0.0.57 |
|
esphome-web-809081 | esphome-web-809081 |
10.0.0.58 |
This is useful, I now have a list of devices to review, and a table to keep notes in!