Event / automation trigger on Rhasspy Wake Word Detection {solved with netdaemon}

Hi everyone

I would like to have a visual signal when Rhasspy detects my wake word.

There is an available websocket:
https://rhasspy.readthedocs.io/en/latest/usage/#websocket-wake

Can someone help me integrate it to have an event or automation trigger in home assistant?
Or has anyone already managed it differently?

What would otherwise be an easy way to create a websocket client in home assistant?

Thanks for reading and any help or ideas :slight_smile:

There is probably an easier solution but I implemented it with a custom implementation in the netdaemon addon:

using System;
using System.IO;
using System.Net.WebSockets;
using System.Reactive.Linq;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using NetDaemon.Common.Reactive;

// Use unique namespaces for your apps if you going to share with others to avoid
// conflicting names
namespace RhasspyWakeWord
{
    /// <summary>
    ///     Rhasspy Wake Word App
    /// </summary>
    public class RhasspyWakeWordApp : NetDaemonRxApp
    {
        public async override void Initialize()
        {
            await InitializeWebSocket();
        }
        private async Task InitializeWebSocket()
        {
            const string Connection = "ws://rhasspy_ip:12101/api/events/wake";
            do
            {
                using (var socket = new ClientWebSocket())
                    try
                    {
                        await socket.ConnectAsync(new Uri(Connection), CancellationToken.None);
                        await Receive(socket);

                    }
                    catch (Exception ex)
                    {
                        LogError($"ERROR - {ex.Message}");
                    }
            } while (true);
        }

        async Task Receive(ClientWebSocket socket)
        {
            var buffer = new ArraySegment<byte>(new byte[2048]);
            do
            {
                WebSocketReceiveResult result;
                using (var ms = new MemoryStream())
                {
                    do
                    {
                        result = await socket.ReceiveAsync(buffer, CancellationToken.None);
                        ms.Write(buffer.Array, buffer.Offset, result.Count);
                    } while (!result.EndOfMessage);

                    if (result.MessageType == WebSocketMessageType.Close)
                        break;

                    ms.Seek(0, SeekOrigin.Begin);
                    using (var reader = new StreamReader(ms, Encoding.UTF8))
                    {
                        var jsonResult = await reader.ReadToEndAsync();
                        var entity = JsonSerializer.Deserialize<WakeWord>(jsonResult, new JsonSerializerOptions{PropertyNameCaseInsensitive = true});
                        if (entity?.WakewordId == "mywakeword")
                        {
                            //lower volume
                            string? mediaPlayerState = State("media_player.mymediaplayer")?.State;
                            var volume = (double?)State("media_player.mymediaplayer")?.Attribute?.volume_level;
                            if (mediaPlayerState == "playing" && volume.HasValue && volume.Value > 0.1)
                            {
                                CallService("media_player", "volume_set", new { entity_id = "media_player.mymediaplayer", volume_level = 0.1 });
                                RunIn(TimeSpan.FromSeconds(7), () => CallService("media_player", "volume_set", new { entity_id = "media_player.mymediaplayer", volume_level = volume }));
                            }

                            //light indicator
                            Entity("light.dashboard_light").TurnOn(new { brightness = 100, effect = "Scan_Slow", color_name = "mediumspringgreen" });
                            RunIn(TimeSpan.FromSeconds(5), () => Entity("light.dashboard_light").TurnOff());
                        }
                    }
               }
            } while (true);
        }
    }

    public class WakeWord
    {
        public string? WakewordId { get; set; }
        public string? SiteId { get; set; }
    }
}