Speaking Clock
The custom sentence and the intent here are simple. The challenge is to get your voice assistant to speak the time naturally - "a quarter to five" instead of "16:45". This is done in a template rather than in the intent script itself.
To use intent scripts you have to install the intent script integration.
Custom sentence
language: "en"
intents:
CustomWhatTime:
data:
- sentences:
- "(What | What's | What is | Tell me) [the] time [is it]"
Intent
CustomWhatTime:
action:
- action: script.tts_response
data:
tts_sentence: It's {{ states('sensor.speaking_clock') }}
Templates
There isn't a way to do this elegantly.
First convert the hour to the 12-hour clock.
- sensor:
- name: "Hour"
state: >
{% if now().strftime('%-I') | int == 0 %}
12
{% else %}
{{ now().strftime('%-I') }}
{% endif %}
Then cover every possible permutation of hours and minutes...
- sensor:
- name: "Speaking clock"
state: >
{% if now().strftime('%-I') | int == 0 and now().strftime('%M') | int == 0 %}
midnight
{% elif states('sensor.hour') | int != 0 and now().strftime('%M') | int == 0 %}
{{ states('sensor.hour') }} o'clock
{% elif now().strftime('%M') | int == 15 %}
a quarter past {{ states('sensor.hour') }}
{% elif now().strftime('%M') | int == 30 %}
half past {{ states('sensor.hour') }}
{% elif now().strftime('%M') | int == 1 %}
{{ now().strftime('%-M') }} minute past {{ states('sensor.hour') }}
{% elif now().strftime('%M') | int == 45 and states('sensor.hour') | int == 12 %}
a quarter to one
{% elif now().strftime('%M') | int % 5 == 0 and now().strftime('%M') | int > 30 and states('sensor.hour') | int == 12 %}
{{ 60 - now().strftime('%-M') | int }} to one
{% elif now().strftime('%M') | int == 59 and states('sensor.hour')| int == 12 %}
one minute to one
{% elif now().strftime('%M') | int > 30 and states('sensor.hour')| int == 12 %}
{{ 60 - now().strftime('%M') | int }} minutes to one
{% elif now().strftime('%M') | int == 45 %}
a quarter to {{ states('sensor.hour') | int +1 }}
{% elif now().strftime('%M') | int % 5 == 0 and now().strftime('%M') | int < 30 %}
{{ now().strftime('%-M') }} past {{ states('sensor.hour') }}
{% elif now().strftime('%M') | int % 5 == 0 and now().strftime('%M') | int > 30 %}
{{ 60 - now().strftime('%-M') | int }} to {{ states('sensor.hour') | int +1 }}
{% elif now().strftime('%M') | int < 30 %}
{{ now().strftime('%-M') }} minutes past {{ states('sensor.hour')}}
{% elif now().strftime('%M') | int == 59 %}
{{ 60 - now().strftime('%M') | int }} minute to {{ states('sensor.hour') | int +1 }}
{% elif now().strftime('%M') | int > 30 %}
{{ 60 - now().strftime('%M') | int }} minutes to {{ states('sensor.hour') | int +1 }}
{% endif %}
Notes
now().strftime('%M') | int % 5 == 0
minutes after or before the hour are divisible by five, therefore "ten past" rather than "ten minutes past".