72 lines
1.9 KiB
Elixir
72 lines
1.9 KiB
Elixir
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
|