njh / ruby-mqtt

Pure Ruby gem that implements the MQTT protocol, a lightweight protocol for publish/subscribe messaging.
http://www.rubydoc.info/gems/mqtt
MIT License
541 stars 135 forks source link

Can't delete the retained will message #88

Closed wuhlcom closed 7 years ago

wuhlcom commented 7 years ago

file1.rb

   will_topic         ="a_will_topic018"
    will_payload       ="a_will_payload018"
    will_payload_empty ="" #to clean the retain will msg
    will_retain        =true
    will_qos           =2
    clientid1          ="autotestcid3"
    clientid2          ="autotestcid4"
    client             = MQTT::Client.new
    client.host        = '192.168.10.200'
    client.username    ="autotest"
    client.password    ="zhilutest"
    client.client_id   =clientid2
    client.keep_alive  =60
    client.set_will(will_topic, will_payload, will_retain) #set retain
    # client.will_qos        =1
    client.connect()
    # client.subscribe([['topichaha', 2]])
      client.get do |topic, message|
        puts "#{topic}:#{message}"
      end

after exec e:>ruby file1.rb,the session will be established, then Ctrl+c kill the session,the will-message will be saved by the server 192.168.10.200

file2.rb

    will_topic         ="a_will_topic018"
    will_payload       ="a_will_payload018"
    will_payload_empty ="" #to clean the retain will msg
    will_retain        =true
    will_qos           =2
    clientid1          ="autotestcid3"
    clientid2          ="autotestcid4"
    client            = MQTT::Client.new
    client.host       = '192.168.10.200'
    client.username   ="autotest"
    client.password   ="zhilutest"
    client.client_id  =clientid2
    client.keep_alive =60
    #empty or nil will-payload  msg detete the will-retain msg of the server failed
    client.set_will(will_topic, nil, will_retain)
    client.connect()
    Thread.new do
      client.get do |topic, message|
        puts "#{topic}:#{message}"
      end
    end
    sleep 5
    client.disconnect

after operate file1.rb, exec e:>ruby file2.rb to delete the retained will ,but failed,I still can recieve the will-msg ·a_will_payload018·

but the mosquitto_sub can do it mosquitto_sub -t a -i autotestcid4 -u autotest -P zhilutest -C 1 -h 192.168.10.200 --will-topic a_will_topic018 --will-payload "" --will-retain

njh commented 7 years ago

Hello,

I haven't used the Last Will and Testament feature for my own applications, so I spent sometime trying to test this and got a bit confused as to why things weren't working!

This didn't work:

puts "Connecting..."
MQTT::Client.connect(
  'iot.eclipse.org',
  :will_topic => 'client19/online',
  :will_payload => 'offline',
  :will_retain => true,
  :keep_alive => 10
) do |client|
    client.publish('client19/online', 'online', retain=true)
    client.subscribe('test')
    sleep 2
end
puts "Done"

But this does:

puts "Connecting..."
client = MQTT::Client.new(
  'iot.eclipse.org',
  :will_topic => 'client19/online',
  :will_payload => 'offline',
  :will_retain => true,
  :keep_alive => 10
)
client.connect
client.publish('client19/online', 'online', retain=true)
client.subscribe('test')
sleep 2
exit

I seems the ruby MQTT client is quite good at sending the 'disconnect' message to the server, so unless you forcibly close the connection, the Will is not sent.

Situations in which the Will Message is published include, but are not limited to: • An I/O error or network failure detected by the Server. • The Client fails to communicate within the Keep Alive time. • The Client closes the Network Connection without first sending a DISCONNECT Packet. • The Server closes the Network Connection because of a protocol error.

Finally, in response to your origin question. In order to clear a retained topic, make sure you set will_payload to the empty string "" and not nil.

So maybe also explicitly clear the retained message before calling disconnect, in addtion to using the Will:

client.publish('client19/online', '', retain=true)

nick.

djrobby commented 3 years ago

I'd like to add that another method that works is by using nil instead of ''

client.publish('client19/online', nil, retain=true)
njh commented 3 years ago

I think that is just because:

irb(main):001:0> nil.to_s
=> ""

But yes, using nil might look nicer in code than an empty string 👍