Here is the template to add to the top of your dashboard yaml when using the raw configuration editor. Make sure you have installed the custom-button-card from HACS first. Other integrations are proximity, companion app (for phone sensors) a configured home zone, and spotify. Most information is optional. Add the variable but leave it blank - it should still render without throwing an error.
Template code for dashboard
button_card_templates:
person_card:
variables:
var_person_entity: Person Entity
var_device_tracker: Location tracking device
var_phone_device_type: Enter iphone or android
var_iphone_wifi_ssid: (iPhone only) phone SSID sensor
var_phone_battery_state: Phone battery state sensor
var_phone_battery_level: Phone battery level sensor
var_phone_ringer_mode: (Android Only) Phone ringer mode sensor
var_phone_ringer_volume: (Android Only) Phone ringer volume level
var_geocoded_location: Entity to provide exact addresses
var_spotify: spotify entity. Leave blank if not used
var_wifi_connection: (Android Only) Phone wifi connection name sensor
var_step_counter: Step counter entity
var_home_proximity: Proximity to home distance sensor
var_activity: Activity detection sensor
var_travel_direction: Proximity to home travel direction sensor
var_map_api_key: geoapify.com map api key
name: null
show_name: false
show_state: false
show_icon: false
show_entity_picture: false
entity: '[[[ return variables.var_person_entity ]]]'
aspect_ratio: 1/1
triggers_update:
- '[[[ return variables.var_activity ]]]'
- '[[[ return variables.var_spotify ]]]'
tap_action:
action: none
styles:
card:
- padding: 0% 0% 0% 0%
custom_fields:
photo:
- position: absolute
- top: 8%
- left: 4%
- width: 38%
- height: 38%
- border: 7px solid var(--primary-color);
- border-radius: 50%
map_area:
- position: absolute
- background-color: var(--primary-color)
- background: |
[[[
if ( states[variables.var_device_tracker]) {
return `url('https://maps.geoapify.com/v1/staticmap?style=osm-bright&width=600&height=230¢er=lonlat:${states[variables.var_device_tracker].attributes.longitude},${states[variables.var_device_tracker].attributes.latitude}&zoom=14.0&marker=lonlat:${states[variables.var_device_tracker].attributes.longitude},${states[variables.var_device_tracker].attributes.latitude};type:material;color:%23ff3421;icontype:awesome&scaleFactor=2&apiKey=${variables.var_map_api_key}')`;
}
]]]
- background-repeat: no-repeat
- background-size: cover;
- width: 100%
- height: 35%
- top: 0%
- left: 0%
- font-size: 8px
zone:
- position: absolute
- justify-self: start
- font-weight: bold
- font-size: 100%
- top: 27%
- left: 53%
- width: 60%
- height: 100%
- text-align: left
- color: black
- font-size: 100%
geolocation:
- position: absolute
- justify-self: start
- font-size: 80%
- top: 36%
- left: 53%
- width: 50%
- text-align: left
- color: var(--primary-text-color)
travel:
- position: absolute
- justify-self: start
- font-size: 80%
- top: 58%
- left: 60%
- width: 50%
- text-align: left
- color: var(--accent-color)
proximity:
- position: absolute
- justify-self: start
- font-size: 90%
- top: 53%
- left: 53%
- width: 50%
- text-align: left
- color: var(--primary-text-color)
battery:
- position: absolute
- justify-self: start
- font-size: 90%
- top: 53%
- left: 10%
- width: 50%
- text-align: left
- color: |
[[[
if ( states[variables.var_phone_battery_level] ) {
if (states[variables.var_phone_battery_level].state <= 15 )
return `red`;
if (states[variables.var_phone_battery_level].state >= 16 && states[variables.var_phone_battery_level].state < 45)
return `orange`;
else
return `green`;
}
]]]
ringer:
- position: absolute
- justify-self: start
- font-size: 90%
- top: 80%
- left: 10%
- width: 50%
- text-align: left
- color: |
[[[
if ( states[variables.var_phone_ringer_mode] ) {
if (states[variables.var_phone_ringer_mode].state == "silent")
return `red`;
else
return `var(--primary-text-color)`;
}
]]]
steps:
- position: absolute
- justify-self: start
- font-size: 90%
- top: 66%
- left: 53%
- width: 50%
- text-align: left
- color: var(--primary-text-color)
wifi:
- position: absolute
- justify-self: start
- font-size: 90%
- top: 66%
- left: 10%
- width: 50%
- text-align: left
- color: |
[[[
if (variables.var_phone_device_type == 'iphone') {
if (states[variables.var_iphone_wifi_ssid]) {
if (states[variables.var_iphone_wifi_ssid].state == 'Not Connected')
return `lightgrey`;
else
return `var(--primary-text-color)`;
}
} else {
if (states[variables.var_wifi_connection]) {
if (states[variables.var_wifi_connection].state == '<not connected>')
return `lightgrey`;
else
return `var(--primary-text-color)`;
}
}
]]]
media_playing:
- position: absolute
- display: flex
- align-items: center
- font-size: 80%
- top: 89%
- left: 0%
- width: 95%
- height: 8%
- color: |
[[[
return `var(--primary-text-color)`;
]]]
- visibility: |
[[[
if ( (states[variables.var_spotify] ) && ( states[variables.var_spotify].state == "playing" ) )
return `visible`;
else
return `hidden`;
]]]
- background-color: |
[[[
return `var(--primary-color)`;
]]]
media_image:
- position: absolute
- justify-self: start
- top: 82%
- left: 80%
- width: 17%
- text-align: left
- color: |
[[[
return `var(--primary-text-color)`;
]]]
- visibility: |
[[[
if ( ( states[variables.var_spotify] ) && (states[variables.var_spotify].state == "playing" ) )
return `visible`;
else
return `hidden`;
]]]
activity:
- position: absolute
- font-size: 80%
- background: white
- display: flex
- align-items: center
- top: 38%
- left: 34%
- width: 10%
- height: 10%
- text-align: center
- color: black
- visibility: |
[[[
if ( states[variables.var_activity] ) {
let var_allowed = 'in_vehicle automotive on_bicycle cycling running still stationary walking on_foot';
let var_activity_state = states[variables.var_activity].state;
if ( var_allowed.toLowerCase().includes(var_activity_state.toLowerCase()) )
return `visible`;
else
return `hidden`;
}
]]]
- border: 4px solid var(--accent-color);
- border-radius: 50%
custom_fields:
map_area: ''
photo: |
[[[
return `<img style="width: 100%;height: 100%; object-fit: contain;" src='${entity.attributes.entity_picture}' >`
]]]
zone: |
[[[
if (`${entity.state}` == 'not_home') {
return `<ha-icon icon="mdi:home-export-outline"
style="width: 10%; height: 10%";>
</ha-icon><span> Away</span>`;
}
if (`${entity.state}` =='home') {
return `<ha-icon
icon="mdi:home"
style="width: 10%; height: 10%;">
</ha-icon><span> ${entity.state}</span>`;
} else {
return `<ha-icon
icon="mdi:map-marker-radius"
style="width: 10%; height: 10%;">
</ha-icon><span> ${entity.state}</span>`;
}
]]]
geolocation: |
[[[
if ( states[variables.var_geocoded_location] ) {
if ( variables.var_phone_device_type == 'iphone')
return `
<span>
${states[variables.var_geocoded_location].attributes['Sub Thoroughfare']}
${states[variables.var_geocoded_location].attributes.Thoroughfare} <br />
${states[variables.var_geocoded_location].attributes.Locality},
${states[variables.var_geocoded_location].attributes['Administrative Area']}
${states[variables.var_geocoded_location].attributes['Postal Code']}
</span>`;
else
return `
<span>
${states[variables.var_geocoded_location].attributes.sub_thoroughfare}
${states[variables.var_geocoded_location].attributes.thoroughfare} <br />
${states[variables.var_geocoded_location].attributes.locality},
${states[variables.var_geocoded_location].attributes.administrative_area}
${states[variables.var_geocoded_location].attributes.postal_code}
</span>`;
}
]]]
travel: |
[[[
if ( states[variables.var_travel_direction] && states[variables.var_travel_direction].state == 'towards' ) {
return `
<span>
Heading Home
</span>`;
} else {
return ` `
}
]]]
battery: |
[[[
if (states[variables.var_phone_battery_state]) {
if (states[variables.var_phone_battery_state].state.toLowerCase() =='charging') {
return `<ha-icon icon="mdi:battery-charging" style="width: 12%; height: 12%; ">
</ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone charging
</span>
</span>`;
} else {
if (states[variables.var_phone_battery_level].state < 11) {
return `<ha-icon icon="mdi:battery-10" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;}
if (states[variables.var_phone_battery_level].state >=10 && states[variables.var_phone_battery_level].state < 20)
return `<ha-icon icon="mdi:battery-20" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 20 && states[variables.var_phone_battery_level].state < 30)
return `<ha-icon icon="mdi:battery-30" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 30 && states[variables.var_phone_battery_level].state < 40)
return `<ha-icon icon="mdi:battery-40" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 40 && states[variables.var_phone_battery_level].state < 50)
return `<ha-icon icon="mdi:battery-50" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 50 && states[variables.var_phone_battery_level].state < 60)
return `<ha-icon icon="mdi:battery-60" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 60 && states[variables.var_phone_battery_level].state < 70)
return `<ha-icon icon="mdi:battery-70" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 70 && states[variables.var_phone_battery_level].state < 80)
return `<ha-icon icon="mdi:battery-80" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 80 && states[variables.var_phone_battery_level].state < 90)
return `<ha-icon icon="mdi:battery-90" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
if (states[variables.var_phone_battery_level].state >= 90 && states[variables.var_phone_battery_level].state <= 100)
return `<ha-icon icon="mdi:battery" style="width: 12%; height: 12%;"> </ha-icon>
<span style="color: var(--text-color-sensor);">
${states[variables.var_phone_battery_level].state}%
<span style="font-size: 80%;" >
phone battery
</span>
</span>`;
}
}
]]]
ringer: |
[[[
if (variables.var_phone_device_type == 'iphone') {
return ` `
} else {
if ( states[variables.var_phone_ringer_mode] ) {
if (states[variables.var_phone_ringer_mode].state == "silent")
return `<ha-icon
icon="mdi:volume-off"
style="width: 12%; height: 12%;">
</ha-icon>
<span style="font-size: 80%;" >
ringer silent
</span>`
if (states[variables.var_phone_ringer_mode].state == "vibrate")
return `<ha-icon icon="mdi:volume-vibrate"
style="width: 12%; height: 12%;">
</ha-icon>
<span style="font-size: 80%;" >
ringer vibrate
</span>`
else
return `<ha-icon
icon="mdi:volume-high"
style="width: 12%; height: 12%;">
</ha-icon>
<span> ${states[variables.var_phone_ringer_volume].state}
<span style="font-size: 80%;" >
ringer level
</span>
</span>`
}
}
]]]
steps: |
[[[
if ( states[variables.var_step_counter] ) {
return `<ha-icon
icon="mdi:walk"
style="width: 12%; height: 12%;">
</ha-icon>
<span>${Math.round(states[variables.var_step_counter].state).toFixed(0)} <span style="font-size: 80%;" >steps today</span></span>`
}
]]]
wifi: |
[[[
if (variables.var_phone_device_type == 'iphone') {
if ( states[variables.var_iphone_wifi_ssid] ) {
if ( states[variables.var_iphone_wifi_ssid].state == 'Not Connected')
return `<ha-icon
icon="mdi:wifi-off"
style="width: 12%; height: 12%;">
</ha-icon>
<span style="font-size: 80%;" >Disconnected</span>`;
else
return `<ha-icon
icon="mdi:wifi"
style="width: 12%; height: 12%;">
</ha-icon>
<span style="font-size: 80%;" > ${states[variables.var_iphone_wifi_ssid].state} </span>`;
}
} else {
if ( states[variables.var_wifi_connection] ) {
if ( states[variables.var_wifi_connection].state == '<not connected>' )
return `<ha-icon
icon="mdi:wifi-off"
style="width: 12%; height: 12%;">
</ha-icon>
<span style="font-size: 80%;" >Disconnected</span>`;
else
return `<ha-icon
icon="mdi:wifi"
style="width: 12%; height: 12%;">
</ha-icon>
<span style="font-size: 80%;" >${states[variables.var_wifi_connection].state}</span>`;
}
}
]]]
media_playing: |
[[[
if ( (states[variables.var_spotify]) && (states[variables.var_spotify].state == "playing" )) {
return `<marquee> <ha-icon
icon="mdi:music"
style="width: 20px; height: 20px;"></ha-icon
<span> ${states[variables.var_spotify].attributes.media_title}
- ${states[variables.var_spotify].attributes.media_artist} </marquee>`;
} else {
return ` `;
}
]]]
media_image: |
[[[
if ((states[variables.var_spotify]) && (states[variables.var_spotify].state == "playing" )) {
return `<img style="width: 100%;height: 100%; object-fit: contain;" src='${states[variables.var_spotify].attributes.entity_picture}' >`;
} else {
return ` `;
}
]]]
proximity: |
[[[
if ( states[variables.var_home_proximity] ) {
return `<ha-icon
icon="mdi:map-marker-distance"
style="width: 12%; height: 12%;">
</ha-icon>
<span>
${Math.round(states[variables.var_home_proximity].state).toFixed(0)}
<span style="font-size: 80%;" >miles from home</span></span>`
}
]]]
activity: |
[[[
if ( states[variables.var_activity] ) {
let var_activity_state = states[variables.var_activity].state.toLowerCase();
if ( var_activity_state == 'in_vehicle' || var_activity_state == 'automotive')
return `<ha-icon icon="mdi:car" style="width: 70%; height: 70%;"></ha-icon>`;
else if ( var_activity_state == 'on_bicycle' || var_activity_state == 'cycling')
return `<ha-icon icon="mdi:bicycle" style="width: 70%; height: 70%;"></ha-icon>`;
else if ( var_activity_state.toLowerCase() == 'running')
return `<ha-icon icon="mdi:run-fast" style="width: 70%; height: 70%;"></ha-icon>`;
else if ( var_activity_state == 'still' || var_activity_state == 'stationary')
return `<ha-icon icon="mdi:sofa" style="width: 70%; height: 70%;"></ha-icon>`;
else if ( var_activity_state.toLowerCase() == 'walking' || var_activity_state == 'on_foot') {
return `<ha-icon icon="mdi:shoe-print" style="width: 70%; height: 70%;"></ha-icon>`;
} else {
return `<ha-icon icon="mdi:map-marker-question-outline" style="width: 70%; height: 70%;"></ha-icon>`;
}
}
]]]
Here is the yaml to create the card. Replace the variables with your entities that match the required settings. If using an iPhone, make sure to set variable var_device_type: to iphone…
Card Yaml
type: custom:button-card
template: person_card
var_person_entity: Person Entity
var_device_tracker: Location tracking device
var_phone_device_type: Enter iphone or android
var_iphone_wifi_ssid: (iPhone only) phone SSID sensor
var_phone_battery_state: Phone battery state sensor
var_phone_battery_level: Phone battery level sensor
var_phone_ringer_mode: (Android Only) Phone ringer mode sensor
var_phone_ringer_volume: (Android Only) Phone ringer volume level
var_geocoded_location: Entity to provide exact addresses
var_spotify: spotify entity. Leave blank if not used
var_wifi_connection: (Android Only) Phone wifi connection name sensor
var_step_counter: Step counter entity
var_home_proximity: Proximity to home distance sensor
var_activity: Activity detection sensor
var_travel_direction: Proximity to home travel direction sensor
var_map_api_key: api key from geoapify.Register to first, its free
Sorry took a while to answer. I was working on one function to show if the person is headed towards home.
Also here is an example card configuration that give my current card
Arcade Bliss Card Config Example
type: custom:button-card
template: person_card
variables:
var_person_entity: person.arcadebliss
var_device_tracker: device_tracker.arcadeblisss_talkie_talkie
var_phone_battery_state: sensor.pixel_8_pro_battery_state
var_phone_battery_level: sensor.pixel_8_pro_battery_level
var_phone_ringer_mode: sensor.pixel_8_pro_ringer_mode
var_phone_ringer_volume: sensor.pixel_8_pro_volume_level_ringer
var_geocoded_location: sensor.pixel_8_pro_geocoded_location
var_spotify: media_player.spotify_arcadebliss
var_wifi_state: binary_sensor.pixel_8_pro_wifi_state
var_wifi_connection: sensor.pixel_8_pro_wifi_connection
var_step_counter: sensor.pixel_8_pro_daily_steps
var_home_proximity: sensor.proximity_home_arcadebliss_distance
var_activity: sensor.pixel_8_pro_detected_activity
var_travel_direction: sensor.proximity_home_arcadebliss_direction_of_travel
var_map_api_key: 1a6a9cbce0fa3fc8ab8537971284caea