Skip to content

Commit

Permalink
Merge pull request #88 from jsittner/locate-a-person
Browse files Browse the repository at this point in the history
Locate a person - Blueprint and View
  • Loading branch information
dinki authored Oct 29, 2024
2 parents 97aed03 + 62e91d6 commit 52eb7bb
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 0 deletions.
171 changes: 171 additions & 0 deletions View Assist dashboard and views/views/locate/locate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
type: custom:button-card
variables:
locatecardversion: 1.0.0
template:
- variable_template
- body_template
styles:
grid:
- grid-template-areas: |
"title status"
"map map"
"assist assist"
- grid-template-columns: 1.5fr 1.5fr
- grid-template-rows: min-content max-content
card:
- background: black
- background-size: cover
custom_fields:
map:
- align-self: center
- justify-self: center
- width: 100%
- height: 100%
- position: absolute
- justify-content: center
- z-index: 1
location:
- align-self: center
- justify-self: center
- position: absolute
- z-index: 2
- top: 70vh
- width: 90%
hold_card:
- align-self: center
- justify-self: center
- position: absolute
- width: 80vw
- z-index: 3
custom_fields:
title: >-
[[[ return new Date().toLocaleTimeString([], { hour: "numeric",
minute: "2-digit" }).toLowerCase(); ]]]
map:
card:
type: map
entities:
- entity: >-
[[[ try {return
hass.states[variables.var_assistsat_entity].attributes.locate_data['person']}
catch { return ""}]]]
theme_mode: |-
[[[ try {
var var_map_mode = hass.states[variables.var_assistsat_entity].attributes.locate_data.map_mode;
return `${var_map_mode}`}
catch { return "dark"}]]]
default_zoom: 15
aspect_ratio: 1.5/1
auto_fit: true
fit_zones: false
card_mod:
style:
ha-map $ ha-entity-marker $: |
.marker {
color: white !important;
background-color: #03a9f4 !important;
opacity: 80% !important;
font-size: 3vw !important;
font-weight: bold !important;
height: 5vw !important;
width: 5vw !important;
}
ha-map$: |
.leaflet-control-attribution {
visibility: hidden;
}
.leaflet-control-zoom {
right: -11px;
top: 24vh;
transform: scale(1.8)
}
ha-icon-button$: |
mwc-icon-button[title="Reset focus"]{
--mdc-icon-size: 65px;
right: -10px !important;
position: relative !important;
display: flex !important
}
location:
card:
type: custom:button-card
custom_fields:
location_text: |-
[[[ try {
var var_location_text = hass.states[variables.var_assistsat_entity].attributes.locate_data.location_text;
return `${var_location_text}`}
catch { return ""}]]]
updated: |-
[[[ try {
var var_tracker = hass.states[variables.var_assistsat_entity].attributes.locate_data.person;
var var_last_changed = new Date(hass.states[var_tracker].last_changed);
const current_date = new Date();
const diff = current_date - var_last_changed;
const minutes = Math.floor(diff / (1000 * 60));
const hours = Math.floor(diff / (1000 * 60 * 60));
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
let last_changed;
if (minutes < 1) {
last_changed = "now";
} else if (minutes < 60) {
last_changed = rtf.format(-minutes, 'minute'); // e.g., "5 minutes ago"
} else if (hours < 24) {
last_changed = rtf.format(-hours, 'hour'); // e.g., "2 hours ago"
} else {
last_changed = rtf.format(-days, 'day'); // e.g., "3 days ago"
}
return `${"last changed "+last_changed}`}
catch { return ""}]]]
show_icon: false
show_name: false
styles:
grid:
- grid-template-areas: |
"location_text"
"updated"
- grid-template-columns: 1fr
- grid-template-rows: 1fr min-content min-content
card:
- justify-content: center
- align-items: center
- padding: 2%
- border-radius: 1vw
- background-color: grey
- border: none
- filter: opacity(75%)
custom_fields:
location_text:
- font-size: 6vh
- color: black
- text-wrap: wrap
- font-weight: bold
- text-align: center
updated:
- font-size: 4vh
- color: black
hold_card:
card:
type: custom:button-card
show_icon: false
show_name: false
tap_action:
action: call-service
service: python_script.set_state
service_data:
entity_id: '[[[ return variables.var_assistsat_entity ]]]'
mode: hold
double_tap_action:
action: call-service
service: python_script.set_state
service_data:
entity_id: '[[[ return variables.var_assistsat_entity ]]]'
mode: normal
styles:
card:
- top: 10vh
- border-radius: 1vw
- background-color: transparent
- height: 90vh
- width: 100vw
- border: none
18 changes: 18 additions & 0 deletions View_Assist_custom_sentences/Locate_a_Person/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Locate a Person

<a href="https://github.com/dinki/View-Assist/blob/main/locate-a-person/View_Assist_custom_sentences/Locate_a_Person/locate_example.png"><img src="https://github.com/dinki/View-Assist/blob/main/locate-a-person/View_Assist_custom_sentences/Locate_a_Person/locate_example.png" width="60%"></a>

[![Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https://github.com/dinki/View-Assist/blob/main/View_Assist_custom_sentences/Locate_a_Person/blueprint-locateaperson.yaml)

This blueprint enables you to display the location of a home assistant user on a map. The map also shows the geocoded address with most recent location update in relative time. If you choose to hold the view, it will provide real-time updates as the tracking device sends new location data.

Requires [locate](https://github.com/dinki/View-Assist/blob/main/locate-a-person/View%20Assist%20dashboard%20and%20views/views/locate/) view

Optional requirements for the geocoded tracker sensor in the companion app:
* The **Background location** needs to be enabled. It can be found in the home assistant mobile app -> settings -> companion app -> Location sensors.
* The **Geolocation sensor** needs to be enabled along with it's setting to **Update sensor with location sensors**. It can be found in the home assistant mobile app -> settings -> companion app -> manage sensors.
* The **Background access** also needs to be enabled. It can be found in the home assistant mobile app -> settings -> companion app -> other settings.

Notes:
* The names should be defined phonetically, as the voice assistant interprets them, followed by the person's name as listed in the People menu under settings. To assist in determining the voice assistant's spelling of the name, a visual display of the name will be shown if it is incorrect.
* The maps pinch-to-zoom and drag controls have been replaced with a tap to hold. The reset focus, along with the plus and minus buttons, function as expected.
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# View Assist - Locate a Person (v 1.0.0)
# Written by - jsittner
blueprint:
name: View Assist - Locate a Person
description: Ask Assist to locate a person (View Assist locateaperson v 1.0.0)
domain: automation
input:
command_prompt:
name: Command Text
description: The phrase you want to use to trigger the automation
default: "(locate|map) [my] {person}"
view_locate:
name: Locate View
description: The View Assist dashboard view used for the locate view
default: /dashboard-viewassist/locate
view_info:
name: Info View
description: The View Assist dashboard view used for the info display
default: /dashboard-viewassist/info
defined_names:
name: Defined Names
description: This is the phonetic name followed by the Person's name as configured in the Home Assistant settings
default: '{"john":"jon","simon":"simon"}'
map_mode:
name: Map Mode Theme
description: This will change the map mode theme
default: dark
selector:
select:
mode: dropdown
options:
- dark
- light
group_entity:
name: Group Entity
description: >-
The group that holds the list of View Assist satellites(example
group.viewassist_satellites)
selector:
entity:
filter:
- domain:
- group
multiple: false
default: group.viewassist_satellites
alias: View Assist - Locate a Person
description: "Ask Assist to locate a person"
variables:
view_locate: !input view_locate
view_info: !input view_info
map_mode: !input map_mode
input_defined_names: !input defined_names
persons_name: "{{ input_defined_names | from_json}}"
group_entity: !input group_entity
target_satellite_device: |-
{% for sat in expand('group.viewassist_satellites') %}
{% if (device_id(sat.attributes.mic_device) == trigger.device_id) or (device_id(sat.attributes.display_device) == trigger.device_id) %}
{{ sat.entity_id }}
{% endif %}
{% endfor %}
target_display_device: "{{ device_id(state_attr(target_satellite_device, 'display_device')) }}"
target_mediaplayer_device: "{{ state_attr(target_satellite_device, 'mediaplayer_device') }}"
target_satellite_device_type: "{{ state_attr(target_satellite_device, 'type') }}"
trigger:
- platform: conversation
command:
- !input command_prompt
condition: []
actions:
- if:
- condition: template
value_template: "{% if trigger.slots.person in persons_name %}true{%endif%}"
then:
- variables:
person_source: "{{ 'person.'+persons_name[trigger.slots.person] }}"
tracker_source: >-
{{ state_attr('person.'+persons_name[trigger.slots.person],
'source') }}
geocoded_source: >-
{% set geocoded = 'sensor.' + tracker_source.split('.', 1)[1] +
'_geocoded_location'%} {{ geocoded }}
location_source: |-
{% if states(person_source) != 'not_home' %}
{{ states(person_source)|capitalize }}
{% elif not states(geocoded_source) in ['unknown'] %}
{{ states(geocoded_source) }}
{% else %}
{{ "Unknown Location" }}
{% endif %}
- set_conversation_response: |-
{% if states(person_source) == 'not_home' %}
{{ persons_name[trigger.slots.person] }} is away.
{% else %}
{{ persons_name[trigger.slots.person] }} is at {{ states(person_source) }}
{% endif %}
- action: python_script.set_state
data:
entity_id: "{{ target_satellite_device }}"
locate_data: >-
{{ {'person': person_source, 'tracker': tracker_source, 'geocoded':
geocoded_source, 'location_text': location_source, 'map_mode': map_mode } }}
- if:
- condition: template
value_template: >-
{% if target_satellite_device_type != 'audio_only' %}true{% else
%}false{% endif %}
then:
- data:
path: "{{ view_locate }}"
target:
device_id: "{{ target_display_device }}"
action: browser_mod.navigate
else:
- action: python_script.set_state
data:
entity_id: "{{ target_satellite_device }}"
title: ""
message: "{{ trigger.slots.person |capitalize}} hasn't been defined"
message_font_size: 6vw
- set_conversation_response: "{{ trigger.slots.person }} hasn't been defined"
- data:
path: "{{ view_info }}"
target:
device_id: "{{ target_display_device }}"
action: browser_mod.navigate
mode: single
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 52eb7bb

Please sign in to comment.