switch mp3 to tts, add genserver to app supervisor tree that periodically checks for newly connected devices and plays their associated tts message

This commit is contained in:
2024-07-17 18:20:05 -04:00
parent 8668405143
commit a085aee5c8
18 changed files with 101 additions and 200 deletions

View File

@@ -16,6 +16,7 @@ defmodule HereIAm.Application do
{Finch, name: HereIAm.Finch},
# Start a worker by calling: HereIAm.Worker.start_link(arg)
# {HereIAm.Worker, arg},
HereIAm.DeviceMonitor,
# Start to serve requests, typically the last entry
HereIAmWeb.Endpoint
]

View File

@@ -0,0 +1,71 @@
defmodule HereIAm.DeviceMonitor do
use GenServer
alias HereIAm.Devices
def start_link(_opts) do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
end
@impl true
def init(state) do
schedule_check()
{:ok, Map.put(state, :connected_ips, %{})}
end
@impl true
def handle_info(:check_devices, state) do
connected_ips = get_connected_ips()
# Determine new devices and TTS
new_devices = MapSet.difference(MapSet.new(connected_ips), MapSet.new(Map.keys(state.connected_ips)))
Enum.each(new_devices, fn ip ->
case Devices.get_device_by_ip(ip) do
{:ok, device} -> play_message(device)
{:error, _reason} -> :ok
end
end)
# Update the registry
new_registry = Map.new(connected_ips, fn ip -> {ip, :connected} end)
schedule_check()
{:noreply, %{state | connected_ips: new_registry}}
end
defp schedule_check() do
Process.send_after(self(), :check_devices, 10_000) # Check every 60 seconds
end
defp get_connected_ips() do
{output, 0} = System.cmd("sudo", ["arp-scan", "-l", "--localnet"])
parse_ips_from_arp_scan(output)
end
defp parse_ips_from_arp_scan(output) do
output
|> String.split("\n")
|> Enum.filter(&String.contains?(&1, "\t")) # Filter lines containing tabs (IP-MAC pairs)
|> Enum.map(&String.split(&1, "\t"))
|> Enum.map(&List.first(&1))
|> Enum.filter(&valid_ip?/1)
end
defp valid_ip?(ip) do
case :inet.parse_address(to_charlist(ip)) do
{:ok, _} -> true
{:error, _} -> false
end
end
defp play_message(%{tts: tts_message}) do
cond do
not is_nil(tts_message) and tts_message != "" -> play_tts(tts_message)
true -> IO.puts("No audio or TTS message to play.")
end
end
defp play_tts(tts_message) do
IO.puts("Playing TTS message: #{tts_message}")
System.cmd("espeak", [tts_message])
end
end

View File

@@ -101,4 +101,11 @@ defmodule HereIAm.Devices do
def change_device(%Device{} = device, attrs \\ %{}) do
Device.changeset(device, attrs)
end
def get_device_by_ip(ip_address) do
case Repo.get_by(Device, ip_address: ip_address) do
nil -> {:error, :not_found}
device -> {:ok, device}
end
end
end

View File

@@ -4,7 +4,7 @@ defmodule HereIAm.Devices.Device do
schema "devices" do
field :ip_address, :string
field :audio, :string
field :tts, :string
timestamps(type: :utc_datetime)
end
@@ -12,7 +12,7 @@ defmodule HereIAm.Devices.Device do
@doc false
def changeset(device, attrs) do
device
|> cast(attrs, [:ip_address, :audio])
|> validate_required([:ip_address, :audio])
|> cast(attrs, [:ip_address, :tts])
|> validate_required([:ip_address, :tts])
end
end