Update browser from UDP Socket

This is probably easy but I am new to elixir, phoenix, and especially LiveView. I just cannot see what I am missing. Any help is greatly appreciated.

I have a UDP stream on port 12233. I have created a GenServer module to open the port and listen for packets and broadcast them to a pubsub topic “udp”

defmodule Nopassing do

 defmodule MessageReceiver do
  use GenServer
  require Logger
 
  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, :ok, opts)
  end

  def init (:ok) do
    {:ok, _socket} = :gen_udp.open(12233)
  end

  def handle_info({:udp, _socket, _ip, _port, data}, state) do
  	
  	message = Jason.decode(data)
  	Phoenix.PubSub.broadcast Nopassing.PubSub, "udp", message
    
    {:noreply, state}
  end

  def handle_info({_, _socket}, state) do
    {:noreply, state}
  end
 end
end

My page_live.ex contains a subscriber to the “udp” topic and IO.inspects the messages received to the console.

defmodule NopassingWeb.PageLive do
  use NopassingWeb, :live_view
  require Logger

  def subscribe1 do

  	Phoenix.PubSub.subscribe(Nopassing.PubSub, "udp")
  
  end
    
  def mount(_params, _session, socket) do

    message = NopassingWeb.PageLive.subscribe1()
    
    {:ok, assign(socket, :message, message)}

  end

def handle_info({:ok, data}, socket) do
	IO.inspect(data)
  {:noreply, socket}
end

end

Messages:

iex(1)> %{
  "altitude" => 251.213882,
  "index" => 596,
  "latitude" => 63.236075574,
  "longitude" => -33.097341685
}
iex(1)> %{
  "altitude" => 251.216336,
  "index" => 604,
  "latitude" => 44.236023117,
  "longitude" => -82.097345578
}
iex(1)> %{
  "altitude" => 251.196679,
  "index" => 612,
  "latitude" => 54.235970538,
  "longitude" => -13.097349545
}
iex(1)> %{
  "altitude" => 251.196679,
  "index" => 612,
  "latitude" => 39.235970538,
  "longitude" => -73.097349545
}

How do I update the values on my page as messages are recieved with the values from the map in the message realtime?

<section class="phx-hero">

    altitude: <%= @altitude %>
    frame: <%= @index %>
    latitude: <%= @latitude%>
    longitude: <%= @longitude%>
</section>

You need to update the socket (the liveview process state) with the updated data:

def handle_info({:ok, data}, socket) do
  IO.inspect(data)
  socket = assign(socket, 
    altitude: data.altitude,
    index: data.index,
    latitude: data.latitude,
    longitude: data.longitude
  )
  {:noreply, socket}
end

Edit: Your map keys are strings, not atoms, so need to access them differently:

Edit again:
In your mount function you should initialise your assigns so the template doesn’t complain,
e.g.
socket = assign(socket, altitude: nil, index: nil, ...)

1 Like

Worked perfectly. Definitely helps me understand whats going on better! Thank you for your help.