Question about GenMQTT

Hi,
These days I am trying to publish data to the mqtt broker with nerves project.
When I try to use the GenMQTT.pulish I find some question.

Below is my code.

defmodule QT do
  use GenMQTT

  def start_link do
    {:ok, pid} = GenMQTT.start_link(__MODULE__, {}, opt())
    pid
  end

  def pb(pidd, data) do
    GenMQTT.publish(pidd, "JP_JACK", data, 1)
  end

  def store_pb(data) do
    pid = start_link()
    pb(pid, data)
  end

  def pipe_pb(data) do
    start_link() |> pb(data)
  end

  defp opt do
    [host: "broker.hivemq.com", port: 1883]
  end

After run mix deps.get
I run with the iex -S mix, when I type QT.store.pb("message") and QT.pipe("message")
both of the result is :ok which should be successful publish. But I can’t get the message. I use the MQTTFX to subscribe the same topic.
However I run the below it works.

pid = QT.start_link
QT.pb(pid, "message")

The result is same as before which is :ok, but with these method I can get the “message” at the
MQTTFX.
These make me really confused.

Appreciate for all the advice and help. Also sorry for the poor typesetting.

I have solve this problem these days.

First:
Change the mix.exs in the nerves project

  def application do
      [mod: {Qt, "ok"}]
  end

Second:
Create a file in lib
qt.ex

Write below in this file. The purpose of this file is to start the GenMQTT and the GenServer. At the same time pass the qt_pid which is the pid of GenMQTT to the GenServer.

   defmodule Qt do
     def start(_type, _nothing) do
       {:ok, qt_pid} = QT.Main.start_link
       QT.Server.start_link(qt_pid)
     end
  end

Third:
Create a file main.ex in lib
Write the code below in the file. The purpose of this file is to be the main function of the GenMQTT.

  defmodule QT.Main do
    use GenMQTT
    def start_link do
      GenMQTT.start_link(__MODULE__, {}, opt)
    end
    def pb(pid, data) do
      GenMQTT.publish(pid, "Topic", data, 1)
    end
    def opt do
       [host: "your_broker_ip", port: 1883]
    end
  end

Fourth:
Create server.ex in lib
Write the below code in it. The purpose of this file is to handle with the command

  defmodule QT.Server do
    use GenServer
    def start_link(qt_pid) do
       {:ok, _pid} = GenServer.start_link(__MODULE__, qt_pid, name: __MODULE__)
    end
    def pb(data) do
       GenServer.cast(__MODULE__, {:pub, data})
    end
    def init(qt_pid), do: {:ok, {qt_pid}}
    def handle_cast({:pub, data}, {qt_pid}) do
      QT.Main.pb(qt_pid, data)
      {:noreply, {qt_pid}}
    end
end

Then run: iex -S mix in the command widow

iex> QT.Server.pb("hello_world")

Then you can see the hello_world through mqttfx

I have also try use supervisor to start both GenServer and GenMQTT, but in the end it fail.

Appreciate for any advise.

I really can’t help you with any of this, I don’t use it, but @gausby, the maintainer of gen_mqtt is an active member of this community, perhaps it helps that I mentioned him :wink:

Also I’d like to say, we use markdown to format the posts, therefore you can use either triple backticks (```) to enclose code or just indent it by 4 spaces. When using the backticks you can also specify which highlighter to use with the usual syntax for fenced code blocks. I’ve edited you post to use fenced blocks, you can view how I did it by clicking edit on your post and view the sources of the post.

1 Like

Thanks a lot for edited my post to use fenced blocks.
This is my first time to publish and reply on the forum. Thanks for teaching me how to use markdown to format the posts. This really looks much better. :smile:

1 Like

Just skimmed the thread; I am a bit busy at the moment, and I am not one-hundred-percent sure on what you are trying to do, but try fixing this line:

def pb(data) do
  GenServer.casr(__MODULE__, {:pub, data})
end

to

def pb(data) do
  GenServer.cast(__MODULE__, {:pub, data})
end

Notice the .cast instead of .casr.

Thanks for taking time reply my question.
The casr is a mistake to type on the forum. Still thanks for reminding. The way I write in the reply is actually work in the command window.
I am using a nerves project and I would like raspberry to keep sending message to the broker. At first I think that I can just use:

defmodule QT do
  use GenMQTT
  def start_link do
    {:ok, pid} = GenMQTT.start_link(__MODULE__, {}, opt())
    pid
  end

  def pb(pid, data) do
      GenMQTT.publish(pid, "JP_JACK", data, 1)
  end

  def pipe_pb(data)
     start_link() |>  pb(data)
  end 

I think that I use the pipe to send the pid to the QT.pb

After get the sensor data, use

QT.pipe_pb(data)

to send the sensor data.
The response in command window is

:ok

However I can’t get the message.
But If I do it seperate.

iex> pid = QT.start_link
iex> QT.pb(pid, "something")

I can get the message: something

I have also try.

  def store_pb(data)
    pid = start_link()
    pb(pid, data)
  end

Same get the response :ok, but can’t get the message.
I have try the

  def store_pb(data)
    pid = start_link()
    IO.inspect(pid)
  end

That the pid is the GenMQTT runnimg on.
If I type:

iex> QT.pb(pid, "something")

I can get the something through mqtt.

So after some trying I think that the GenMQTT should be start in another way.
Then turn out my reply. I use the

def application do
  [mod: {Qt, "ok"}]
 end

to start the GenMQTT and store its pid in the GenServer.

Is that the GenMQTT should be start like this or through supervisor.

Appreciate for any response.