400: Bad Request Response to TTS speak service called through HA API

Hello,

I’m currently trying to make one of my smart speakers to say things via the home assistant API. I want a device on my network to be able to ‘speak’ text through the speaker using a HTTP POST.

Here’s a python code snippet I’ve been using to make the request. I’ve tried a bunch of different arrangements to the request, but I get 400: Bad Request back from home assistant for each one. I’ve also tried using curl, which also didn’t work.

def say():
    url = "http://192.168.11.110:8123/api/services/tts/speak"  # updated service URL
    data = {
        "target": {"entity_id":"tts.google_en_com"},
        "media_player_entity_id": "media_player.living_room_speaker",
        "message": "Hello there"
    }
    response = requests.post(url, headers=headers, json=data)
    print(response.text)

I changed the logging level to info, and here’s an example of a log entry for the call (note the ‘Invalid data’ on the last line, this isn’t the exact one from above, but that gives a very similar result)

2023-11-20 12:55:51.477 DEBUG (MainThread) [homeassistant.components.http.auth] Authenticated 192.168.11.10 for /api/services/tts/speak using bearer token
2023-11-20 12:55:51.477 DEBUG (MainThread) [homeassistant.components.http.view] Serving /api/services/tts/speak to 192.168.11.10 (auth: True)
2023-11-20 12:55:51.480 DEBUG (MainThread) [homeassistant.core] Invalid data for service call tts.speak: {'media_player_entity_id': 'media_player.living_room_speaker', 'message': 'Hello there'}

It looks like the authentication is good, but the data I’m sending is bad. I’ve tried a whole bunch of different things, and I can’t get it working. I got a button on the dashboard to say some text through the speaker, and that works just fine. Here’s the yaml for the button:

show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: tts.speak
  target:
    entity_id: tts.google_en_com
  data:
    cache: true
    media_player_entity_id: media_player.living_room_speaker
    message: THIS IS A TEST!  hello, hello

Finally, I used the homeassistant/api/services endpoint to find the tts speak service, here’s the output from that:

"domain":"tts",
      "services":{
         "speak":{
            "name":"Speak",
            "description":"Speaks something using text-to-speech on a media player.",
            "fields":{
               "media_player_entity_id":{
                  "required":true,
                  "selector":{
                     "entity":{
                        "domain":"media_player"
                     }
                  },
                  "name":"Media player entity",
                  "description":"Media players to play the message."
               },
               "message":{
                  "example":"My name is hanna",
                  "required":true,
                  "selector":{
                     "text":null
                  },
                  "name":"Message",
                  "description":"The text you want to convert into speech so that you can listen to it on your device."
               },
               "cache":{
                  "default":true,
                  "selector":{
                     "boolean":null
                  },
                  "name":"Cache",
                  "description":"Stores this message locally so that when the text is requested again, the output can be produced more quickly."
               },
               "language":{
                  "example":"ru",
                  "selector":{
                     "text":null
                  },
                  "name":"Language",
                  "description":"Language to use for speech generation."
               },
               "options":{
                  "advanced":true,
                  "example":"platform specific",
                  "selector":{
                     "object":null
                  },
                  "name":"Options",
                  "description":"A dictionary containing integration-specific options."
               }
            },
            "target":{
               "entity":[
                  {
                     "domain":[
                        "tts"
                     ]
                  }
               ]
            }
         }

I’m using the home assistant raspberry pi image on a raspberry pi 3b+. The Home Assistant OS Version is 11.0, and Home Assistant Core version is 2023.10.3.

Has anyone else had this problem? Anyone have any ideas what might be wrong? I’ve went through a bunch of examples and haven’t had any luck. Thanks!

1 Like

Anyone have any ideas about this? I also tried to make my request match the service specification from homeassistant/api/services, but I still get the 400: Bad Request

data = {
        "target": {
            "entity":[
                {"entity_id":"tts.google_en_com"}]},
        "fields": {
            "media_player_entity_id": "media_player.living_room_speaker",
            "message": "Hello there"
        }
    }

If you are still trying to get this to work, I had success with a “flat” json object:

{
  "media_player_entity_id":"media_player.mp_office_1_104560_office_media_player_104560",
  "message":"Jayden for heisman",
  "cache":false,
  "entity_id":"tts.piper"
}

My actual curl command:

curl \
        -s\
        -H "Content-Type: application/json"\
        -H "Authorization: Bearer ${ha_key}"\
        -d '{"media_player_entity_id":"media_player.mp_office_1_104560_office_media_player_104560","message":"Jayden for heisman","cache":false,"entity_id":"tts.piper"}'\
        "${ha_url}/api/services/tts/speak" | jq '.'

returned:

[
  {
    "entity_id": "tts.piper",
    "state": "2024-01-07T16:19:46.425656+00:00",
    "attributes": {
      "friendly_name": "piper"
    },
    "last_changed": "2024-01-07T16:19:46.425697+00:00",
    "last_updated": "2024-01-07T16:19:46.425697+00:00",
    "context": {
      "id": "01HKJBJ7KQNJD57JT0XF4THTJG",
      "parent_id": null,
      "user_id": "e006d7ed16d1423db5a95f2be5ea007a"
    }
  }
]

1 Like

I just saw this. I had given up working on it. But this totally works! Thanks so much!

I also had to change my Local Network URL to my Home Assistant instant under the Home Assistant URL in Settings → System → Network. Without this, the speaker would beep, and then fail to play the file generated by tts.