How to say the time in a normal sounding way using Piper TTS?

I have a couple of automations that bug me every 30 minutes until I either dismiss it or start something… Part of the bugging me is speaking the time through a media player using Piper TTS.

I’ve tried anything I can find, but I just cannot get TTS to say the time in a way that doesn’t sound really awkward.

Its {{now().strftime('%I %M %p')}}.

…is the closest I’ve got, but for 01:00am it says “Its zero one zero zero AM”.

How can I have Piper TTS say the time more like a human, doing the following:
If hour == 00 say 12
Don’t pad hours to two characters (so zero one becomes just one)
If minutes == 00, don’t say them
A clear A.M. or P.M. rather than saying am (like ham without the h) or pum

Logically it’s really simple, but tbh I find HAs syntax really difficult/frustrating and can rarely do what I’m hoping for unless its something very simple or using the gui view.
I spend half my time swearing at indecipherable error messages, trying to bend examples to do what I want but they break in some horrid way as soon as I breathe near them, reading other people struggle, or at best finding something that works but has no explanation so I can’t learn much from it. :person_facepalming:

I don’t think it’s just me being dumb, I’m generally very IT/tech-savvy, and can churn out arduino code just fine, for example - but whatever needs to click for me to be able to talk HA just isn’t. I’ve been messing with speaking the time for hours, and it still makes me cringe half the times it runs! I don’t really mean to whinge as I ask for a hand, but as soon as I try to stray from the simplest of things HA can quickly become very unfriendly.

Is there any advice anyone could give for progressing my understanding of how to write scripts and automations in HA, past whats available using the gui view?
Thanks very much

Hi mad-tunes,

This awesome custom template exists. You can pull it in thru HACS.
GitHub - Petro31/easy-time-jinja: Easy Time calculations for Home Assistant templates.

Thanks. I got lucky and found copy/pasting this:

    {% from 'easy_time.jinja' import clock %}
    Its {{ clock() }}, go to bed.

…seems to do OK right this minute. But I can’t find how to manualy pass it a time to test it without hitting things like:

Message malformed: template value should be a string for dictionary value @ data['actions'][0]['choose'][0]['sequence'][0]['then'][4]['data']

or

Invalid action
template value should be a string for dictionary value @ data[0]['data']

or

Error running action
Error rendering data template: UndefinedError: 'easy_time' is undefined

So I’m still stuck in the same place. It might be great, but as soon as I stray from copy/paste HA just shows me its middle finger.

Have I found what you were suggesting, and do you know if t’ll do what I’m hoping for pls?

It just said “Its three zero zero AM”, so the only thing I’ve got to run from Easy Time isn’t any closer to what I’m hoping for. :tired_face:

This is the pair of macros I use to get around the “three zero zero AM” issue:

{% macro _round_min(t, round_min) %}
{% set h_offset = 0 %}
{% set min = (t.minute // round_min) * round_min
if (t.minute % round_min) < round_min/2 
else ((t.minute + round_min) // round_min) * round_min%}
{% if min == 60 %}
  {% set min = '00' %}
  {% set h_offset = 1 %}
{% elif min == 0 %}
  {% set min = '00' %}
{% endif %}  
{{(t.hour + h_offset)~':'~min~':00'}}
{% endmacro %}

{%- macro say_time(t, round_min=0) %}
{% if t is undefined or not(t is datetime) %}
  Macro Arg Type Error: First argument must be a datetime object
{% elif round_min is defined and not(round_min is integer) %}
  Macro Arg Type Error: Second argument must be an integer
{% else %}
  {%- if round_min != 0 %}
    {%- set t = today_at(_round_min(t, round_min)) %}
  {%- endif %}
  {%- if t.hour in  [0, 12] and t.minute ==  0 %}
    {{- 'midnight' if t.hour == 0 else 'noon' }}
  {%- elif t.minute ==  0 %}
    {{- t.strftime('%-I') }} o'clock {{ t.strftime('%p') }}
  {%- elif t.minute <  10 %}
    {{- t.strftime('%-I Oh %-M %p' ) }}
  {%- else %}
    {{- t.strftime('%-I:%M %p') }}
  {%- endif -%}{% endif %}
{%- endmacro %}

I have them in a file called speech_macros.jinja, so the action looks like:

action: tts.speak
data:
  media_player_entity_id: media_player.example
  message: |
    {% from 'speech_macros.jinja' import say_time %}
    It's {{ say_time(now()) }}, go to bed.
target:
  entity_id: tts.piper
1 Like

Thanks.

Where should this file go though please?
Creating a file of this name in the config folder leads to actions giving
Error running action Error rendering data template: TemplateNotFound: speech_macros.jinja

Similar if I put the file in \config\custom_templates

My next best guess is that it might need to be a script. Add it as one of those and the editor lights up red like it doesnt like any of it, and I still get the same message if I try to use it.

What am I missing please?

Did you reload the macros?

You can call this action from Developer Tools → Actions:

homeassistant.reload_custom_templates

Putting it in \config\custom_templates\ and running homeassistant.reload_custom_templates in dev tools has got it to run. Thanks a lot.

It’s run OK for right now. I’m struggling to manually pass it a time to test it though.
Swapping the now() for a date/time seems reasonable, but whatever format I try, when I run it my speaker says it must be a ‘data time object’.
I’ve tried times and datetimes in various formats, but am always told the same.

To get a datetime object from a simple time use today_at().

{% from 'speech_macros.jinja' import say_time %}
It's {{ say_time(today_at('23:00')) }}, go to bed.
1 Like

It seems to work really well. Thanks again.

I’d like to understand how it works, but can’t decipher it.
Is there any way of understand this that anyone could suggest please?
Having it working is great, but not understanding it means I’ll be stuffed if it ever has a problem (as has happened with various changes in other areas of HA before now, like my perectly working voice assistant that’s been useless since some change in esphome months ago now) or I’d like to change it.

You used the wrong macro in easy_time, you should have used clock_phrase.

I’d have a read and try to get it going, but I can’t find any mention of using clock_phrase in the documentation?

I see it in easy_time.jinja, which seems to suggest it could be run for the current time without any arguments… When I have my best guess like this:

    {% from 'easy_time.jinja' import clock %}
    It's {{ clock_phrase() }}.

that produces Error running action Error rendering data template: UndefinedError: 'clock_phrase' is undefined

How should it be used please?

    {% from 'easy_time.jinja' import clock_phrase %}
    It's {{ clock_phrase() }}.

That gives me:

Error running action

Error rendering data template: UndefinedError: the template 'easy_time.jinja' (imported on line 1) does not export the requested name 'clock_phrase'

Hmm, maybe I forgot to make a release.

I’ll look into it when I get home tonight.

Thanks. If there’s a better approch, it’d be great if it could work.

This conversation really does illustrate my frustration with anything outside HAs GUI though.

Try to figure something out and spend ages getting nowhere so resort to asking for a hand, ‘This exists’, ‘How do I try it?’, ‘Got it to run but its no better’, ‘try this other thing’, ‘how do I try this other thing?’, ‘like this’, ‘that seems good’, ‘its wrong’, ‘hows the right thing work?’, ‘it doesn’t’.
For hours and hours and hours, just to say the time in a way that doesn’t make it sound like HA needs to find a window to lick.

I honestly don’t mean to complain about people being helpful, I appreciate all of the suggestions, it just seems to be the reality of it with most questions I’ve had. Is there someting I’m doing wrong, or could do differently, to make this kind of conversation better for everyone?

Most of HA is tinkering, especially with new things like voice.

I’m well up for tinkering, and tbh hate it if I can’t. I’m one of those annoying folks who’s always taken everything apart since I was a kid.
I’ve honestly never found anything else as frustrating though.
My DIY voice assistant is probably the worst example. A big ‘marketing’ push with the Year of the voice (or whatever it was), I spend a long lime cobbling together my own assistant that worked a treat. A couple of months later it’s broken by an update and so far has stayed that way, whatever I try. Not a single useful reply to the issue I raised, and not a single working example to dig into. For me at least, it’s wasted considerable time/effort I’ve put into HA.

I might just have to write if off as a simple gui-driven ‘if this then that’ to twiddle devices on and off, which would be a shame.
I don’t have much hair left to tear out! :weary:

Maybe I’m just not good at picking which bits if HA to invest time in, or hoping to do pretty simple seeming things somehow isn’t right?
There’s got to be a way to explore what HA can do without ending up hating it, surely? (honestly, I’m open to suggestions)

Again, sorry this probably comes across as whinging about not being bright enough to use HA, but I’m just too close to nuking my HA VM and doing something more constructive while turning lights on/off using light switches.

Made a new release, forgot to push those changes awhile ago. Oops. Anyways this will work now

    {% from 'easy_time.jinja' import clock_phrase %}
    It's {{ clock_phrase() }}.

It still may not be what you’re looking for though as it reads a bit different than Drew’s macro.

e.g. half past 10, noon, midnight, quarter to 5, etc.

2 Likes

I like the idea of the more human sounding way, so just updated to 2.1.0.1 and had a play. Seems to work a treat.
@Didgeridrew’s script worked well for saying the time as numbers though, I’ll defnitely keep that stashed for another time.

Thank you both again, I’d been bashing my head against this for too long.
(I hadn’t even found template macros existed, so Ive some reading to do now!)