Sending wav File to rhasspy client

I would like to send a wav file to one of my zeros (Alarm) with node red.
I can do this with curl:
curl -X POST “http://10.2.30.1:12101/api/play-wav” -H “Content-Type: audio/wav” --data-binary @"/home/kaykoch/beep.wav"

I tried it with node red:


[{“id”:“193b6f2e.e444e1”,“type”:“http request”,“z”:“eefcaba0.cea7d8”,“name”:"-> Wohnzimmer",“method”:“POST”,“ret”:“bin”,“paytoqs”:false,“url”:“http://10.2.30.1:12101/api/play-wav",“tls”:"",“persist”:false,“proxy”:"",“authType”:"",“x”:680,“y”:1060,“wires”:[[]]},{“id”:“5d7e7c8d.179844”,“type”:"file in”,“z”:“eefcaba0.cea7d8”,“name”:"",“filename”:"/data/beep.wav",“format”:"",“chunk”:false,“sendError”:false,“encoding”:“none”,“x”:480,“y”:1100,“wires”:[[“b1eeeb0f.064a48”,“193b6f2e.e444e1”]]},{“id”:“6bcc905f.a777”,“type”:“inject”,“z”:“eefcaba0.cea7d8”,“name”:"",“topic”:"",“payload”:"",“payloadType”:“date”,“repeat”:"",“crontab”:"",“once”:false,“onceDelay”:0.1,“x”:220,“y”:1100,“wires”:[[“5d7e7c8d.179844”]]},{“id”:“b1eeeb0f.064a48”,“type”:“debug”,“z”:“eefcaba0.cea7d8”,“name”:"",“active”:true,“tosidebar”:true,“console”:false,“tostatus”:false,“complete”:“payload”,“targetType”:“msg”,“x”:670,“y”:1140,“wires”:[]}]

The wav file is recognized, but no sound at zero.
file-in sends wav as single buffer object to /api/play-wav

may you help me?

Does your flow set the Content-Type header? If it’s not set to audio/wav, Rhasspy will interpret the incoming data as a URL and try to download it before playing.

1 Like

Thats it. Thank you.

1 Like

Hello,
could you please post your nodered flow as preformatted text so that I can import it ?
I´m trying to send wav files in the same way.
Thank you !

Hi,

I would also love to know if there is a way of sending a .wav through mqtt to a satellite? I assume there is, but I am not a great programmer and would love a mqtt pub example or just explain it like I am 5 (ELI5) kind of thing. Also I have done a lot of googling and I can’t seem to find what .wav specs work with Rhasspy, I found 3 variations so far :frowning:

Thanks

For Rhasspy to play a wav file, a message can be send to the endpoint api/play-wav

This can be done by three methods:

  • set Content-Type to “audio/wav”, the data you post will be assumed raw data
  • Post a string starting with “/”, then the wav file from that path will be played (so the file should be on the filesystem of Rhasspy
  • post a url, the wav file from that url will be played.

If you want it to play on a certain satellite, you must include the siteId in the querystring on the endpoint, see the reference

1 Like

Hello,
I follow this post, due the @romkabouter answer (three methods to send a wav file to the endpoint api/play-wav).
Something is wrong with my script in hom assistant, and I don’t know why. Some help would be appreciate :
configuration.yaml

rest_command:   
  rhasspy_play:                                 
    url: 'http://192.168.1.6:12101/api/play-wav'
    method: POST
    headers:
      content_type: 'audio/wav'
    payload: '{{ payload }}'

automation.yaml

- id: '1636909817124'                          
  alias: Il est l or                           
  description: ''                              
  trigger:                                     
  - platform: event                            
    event_type: rhasspy_GetTimePlus            
  condition: []                                
  action:                            
  - service: rest_command.rhasspy_play
    data:                              
      payload: /home/pi/var/lib/docker/volumes/Media/_data/monsignor.wav
  mode: single

I followed this post : Rhasspy offline voice assistant toolkit - #585 by koan - Custom Components - Home Assistant Community, and the curl command works…

Here my logs:
On Rhasspy :

[ERROR:2021-11-28 17:06:45,214] rhasspyserver_hermes: 
Traceback (most recent call last):
  File "/usr/lib/rhasspy/.venv/lib/python3.7/site-packages/quart/app.py", line 1821, in full_dispatch_request
    result = await self.dispatch_request(request_context)
  File "/usr/lib/rhasspy/.venv/lib/python3.7/site-packages/quart/app.py", line 1869, in dispatch_request
    return await handler(**request_.view_args)
  File "/usr/lib/rhasspy/rhasspy-server-hermes/rhasspyserver_hermes/__main__.py", line 1135, in api_play_wav
    await asyncio.gather(*aws)
  File "/usr/lib/rhasspy/rhasspy-server-hermes/rhasspyserver_hermes/__init__.py", line 761, in play_wav_data
    raise RuntimeError(result.error)
RuntimeError
[DEBUG:2021-11-28 17:06:45,211] rhasspyserver_hermes: Publishing 44 bytes(s) to hermes/asr/toggleOn
[DEBUG:2021-11-28 17:06:45,210] rhasspyserver_hermes: -> AsrToggleOn(site_id='default', reason=<AsrToggleReason.PLAY_AUDIO: 'playAudio'>)
[DEBUG:2021-11-28 17:06:45,206] rhasspyserver_hermes: Publishing 44 bytes(s) to hermes/hotword/toggleOn
[DEBUG:2021-11-28 17:06:45,204] rhasspyserver_hermes: -> HotwordToggleOn(site_id='default', reason=<HotwordToggleReason.PLAY_AUDIO: 'playAudio'>)
[ERROR:2021-11-28 17:06:45,201] rhasspyserver_hermes: AudioPlayError(error='', site_id='default', context='14dbe5e0-5a0e-4a86-8588-435be17d688c', session_id='14dbe5e0-5a0e-4a86-8588-435be17d688c')
[DEBUG:2021-11-28 17:06:45,196] rhasspyserver_hermes: Handling AudioPlayError (topic=hermes/error/audioServer/play, id=873f37c0-32f0-4104-885f-909bb98f94d4)
[DEBUG:2021-11-28 17:06:45,126] rhasspyserver_hermes: -> AudioPlayBytes(49 byte(s))
[DEBUG:2021-11-28 17:06:45,125] rhasspyserver_hermes: Publishing 44 bytes(s) to hermes/asr/toggleOff
[DEBUG:2021-11-28 17:06:45,124] rhasspyserver_hermes: -> AsrToggleOff(site_id='default', reason=<AsrToggleReason.PLAY_AUDIO: 'playAudio'>)
[DEBUG:2021-11-28 17:06:45,120] rhasspyserver_hermes: Publishing 44 bytes(s) to hermes/hotword/toggleOff
[DEBUG:2021-11-28 17:06:45,119] rhasspyserver_hermes: -> HotwordToggleOff(site_id='default', reason=<HotwordToggleReason.PLAY_AUDIO: 'playAudio'>)
[DEBUG:2021-11-28 17:06:45,115] rhasspyserver_hermes: Playing 49 byte(s)

On HomeAssistant :

{
  "trace": {
    "last_step": "action/0",
    "run_id": "1",
    "state": "stopped",
    "script_execution": "finished",
    "timestamp": {
      "start": "2021-11-28T16:06:45.083446+00:00",
      "finish": "2021-11-28T16:06:45.238360+00:00"
    },
    "domain": "automation",
    "item_id": "1636909817124",
    "trigger": "event 'rhasspy_GetTimePlus'",
    "trace": {
      "trigger/0": [
        {
          "path": "trigger/0",
          "timestamp": "2021-11-28T16:06:45.083724+00:00",
          "changed_variables": {
            "this": {
              "entity_id": "automation.il_est_l_or",
              "state": "on",
              "attributes": {
                "last_triggered": "2021-11-28T16:02:57.703089+00:00",
                "mode": "single",
                "current": 0,
                "id": "1636909817124",
                "friendly_name": "Il est l or"
              },
              "last_changed": "2021-11-28T16:02:31.228286+00:00",
              "last_updated": "2021-11-28T16:02:57.860542+00:00",
              "context": {
                "id": "08837849727a7c4311fdd651f7d25c95",
                "parent_id": "1d0960c79b007410c832df161474a3e7",
                "user_id": null
              }
            },
            "trigger": {
              "id": "0",
              "idx": "0",
              "platform": "event",
              "event": {
                "event_type": "rhasspy_GetTimePlus",
                "data": {},
                "origin": "REMOTE",
                "time_fired": "2021-11-28T16:06:45.077844+00:00",
                "context": {
                  "id": "1f66ff995acb54b5194898ae977e955e",
                  "parent_id": null,
                  "user_id": "8a26e4e5b8004e7990da6f5e74f2f46c"
                }
              },
              "description": "event 'rhasspy_GetTimePlus'"
            }
          }
        }
      ],
      "action/0": [
        {
          "path": "action/0",
          "timestamp": "2021-11-28T16:06:45.087196+00:00",
          "changed_variables": {
            "context": {
              "id": "c091b5a6e6af2f6a7cf2aaea6d62a297",
              "parent_id": "1f66ff995acb54b5194898ae977e955e",
              "user_id": null
            }
          },
          "result": {
            "params": {
              "domain": "rest_command",
              "service": "rhasspy_play",
              "service_data": {
                "payload": "/var/lib/docker/volumes/Media/_data/monsignor.wav"
              },
              "target": {}
            },
            "running_script": false,
            "limit": 10
          }
        }
      ]
    },
    "config": {
      "id": "1636909817124",
      "alias": "Il est l or",
      "description": "",
      "trigger": [
        {
          "platform": "event",
          "event_type": "rhasspy_GetTimePlus"
        }
      ],
      "condition": [],
      "action": [
        {
          "service": "rest_command.rhasspy_play",
          "data": {
            "payload": "/var/lib/docker/volumes/Media/_data/monsignor.wav"
          }
        }
      ],
      "mode": "single"
    },
    "blueprint_inputs": null,
    "context": {
      "id": "c091b5a6e6af2f6a7cf2aaea6d62a297",
      "parent_id": "1f66ff995acb54b5194898ae977e955e",
      "user_id": null
    }
  },
  "logbookEntries": [
    {
      "name": "Il est l or",
      "message": "has been triggered by event 'rhasspy_GetTimePlus'",
      "source": "event 'rhasspy_GetTimePlus'",
      "entity_id": "automation.il_est_l_or",
      "context_id": "c091b5a6e6af2f6a7cf2aaea6d62a297",
      "when": "2021-11-28T16:06:45.084351+00:00",
      "domain": "automation"
    }
  ]
}

Any idea ?
Thanks
Damien

I think you must not set the “content_type: ‘audio/wav’” in yout rest_command.

Because these are the methods;

  • set Content-Type to “audio/wav”, the data you post will be assumed raw data
  • Post a string starting with “/”, then the wav file from that path will be played (so the file should be on the filesystem of Rhasspy
  • post a url, the wav file from that url will be played.

You are mixing 1 and 2 (filepath + audio/wav header)
The rest_command sets the header, but the payload is not raw audio but a filepath

Thanks @romkabouter, so I change without the Content-Type command line. Unfortunately I still have an error message.

The command aplay var/lib/docker/volumes/Media/_data/monsignor.wav works perfectly, but the error message indicates “no soch file or directory” (see above).

I see two potentials problems :
1- No right to access to the file (but aplay works without sudo command), moreover, the access is

pi@raspberrypi:/ $ ls -l var/lib/docker/volumes/Media/_data
total 656
-rw-r--r-- 1 pi pi 223608 nov.   8 18:01 monsignor.mp3
-rw-r--r-- 1 pi pi 444332 nov.  14 11:30 monsignor.wav

2- your comments

But, i’m noob and I don’t unstertand what’s the implication. Rhasspy is on docker, so do i need to mount directory to var/lib/docker/volumes/Media/_data ? If so, frome where in Rhasspy ?
The /_data directory is the share directory for Homeassistant (also in docker).

Thanks for your help and advices !

[ERROR:2021-11-29 21:30:46,766] rhasspyserver_hermes: [Errno 2] No such file or directory: '/var/lib/docker/volumes/Media/_data/monsignor.wav'
Traceback (most recent call last):
  File "/usr/lib/rhasspy/.venv/lib/python3.7/site-packages/quart/app.py", line 1821, in full_dispatch_request
    result = await self.dispatch_request(request_context)
  File "/usr/lib/rhasspy/.venv/lib/python3.7/site-packages/quart/app.py", line 1869, in dispatch_request
    return await handler(**request_.view_args)
  File "/usr/lib/rhasspy/rhasspy-server-hermes/rhasspyserver_hermes/__main__.py", line 1126, in api_play_wav
    wav_bytes = Path(url_or_path).read_bytes()
  File "/usr/lib/python3.7/pathlib.py", line 1192, in read_bytes
    with self.open(mode='rb') as f:
  File "/usr/lib/python3.7/pathlib.py", line 1186, in open
    opener=self._opener)
  File "/usr/lib/python3.7/pathlib.py", line 1039, in _opener
    return self._accessor.open(self, flags, mode)
FileNotFoundError: [Errno 2] No such file or directory: '/var/lib/docker/volumes/Media/_data/monsignor.wav'
[DEBUG:2021-11-29 21:30:46,743] rhasspyserver_hermes: Loading WAV data from /var/lib/docker/volumes/Media/_data/monsignor.wav

Damien

Ah ok! I assumed an install via deb because you have /home/pi in the filepath.
The filepath should be reachable from the Rhasspy docker container. One place where Rhasspy docker has access to is the folder where the profiles are.
I do not know what your docker command looks like, but the volume mapped to /profiles is the one you want.
I am not sure, but I think then a path like /profiles/monsignor.wav might work if you put that wave file there.

The removing of the header worked though, because now the error is a path now found instead of Rhasspy just publishing the string as raw audio (which obviously fails)

1 Like

Well, I tried, as you could see, the /home/pi path because I feel there was something wrong with the file’s access… But I am not so experienced/skilled to find the good solution…
So, thanks for your advice ! with a new container (and volume), it works perfectly !

Here my docker command (to share with other). I will post on HA community too, because it was really hard for me to correctly configure HA+Rasspy on container.
I have no choice of this container approach, due to the use of seed4mic (reSpeaker HAT is not suitable with rhasspy add-on)…

Again, big thanks !

docker run -p 12101:12101 \
      -v "$HOME/.config/rhasspy/profiles:/profiles" \
      -v "/etc/localtime:/etc/localtime:ro" \
      -d --restart unless-stopped \
      -v /var/lib/docker/volumes/Media/_data:/profiles/Media \
      --device /dev/snd:/dev/snd \
      --name rhasspy \
      rhasspy/rhasspy \
      --user-profiles /profiles \
      --profile fr
1 Like

How do you “Post a string” using curl? I’ve tried using -d ‘/path/to/file’ and curl gives and error saying file not found, which of course it can’t find because the filepath is the one local to Rhasspy, not the machine I’m running curl from.

Please post your command so we can check it

curl -X POST 'http://localhost:12101/api/play-wav' -d '/local/docker/path/to/wav/file.wav'

This works for me:

curl -X POST http://192.168.43.54:12101/api/play-wav -d "/share/rhasspy/profiles/nl/sounds/beep_hi.wav"

Take note that the filepath should be available in the docker container. So it depends on how your volumes are mapped. My example is the Rhasspy Addon