# sudo apt-get install python-software-properties # sudo apt-add-repository ppa:brightbox/ruby-ng # sudo apt-get update # sudo apt-get install ruby2.1
# gem install sinatra-websocket
# gem install mqtt
# encoding: utf-8 require 'sinatra-websocket' require 'mqtt' require 'pp' require 'time' class MyApp < Sinatra::Application # 유저 화면을 출력한다. # index 페이지는 MQTT 서버 정보입력을 위한 UI와 # MQTT 서버로 부터의 Push 메시지를 출력하기 위한 UI가 있다. get "/" do @title = "MQTT Push Test" erb :index end # 유저가 Websocket을 사용하지 않고 /mqtt에 접근할 경우 # 에러페이지를 출력한다. get "/error" do erb :error end # index 페이지에서 MQTT 서버정보를 입력하고 submit 하면 # websocket 페이지로 프로토콜 change 한다. # qos는 사용하지 않는다.(귀찮아서) get "/mqtt" do ip = params[:ip] port = params[:port] qos = params[:qos] topic = params[:topic] # websocket 연결이 아니면 에러 페이지로 보낸다. if !request.websocket? erb :error else request.websocket do |ws| ws.onopen do # MQTT 서버에 연결한 후 topic을 subscribe 한다. MQTT::Client.connect(:host=>ip, :port=>port) do | conn | conn.get(topic) do |topic, message| message = message.force_encoding("UTF-8") ws.send "{\"time\":\"#{Time.new.to_s}\",\"msg\":\"#{message}\"}" end end end ws.onmessage do |msg| end ws.onclose do puts "Web socket close" end end end end end
# cat index.erb <script> function mqtt(ip, port, qos, topic) { var ws = new WebSocket('ws://'+window.location.host+'/mqtt?ip='+ip+'&topic='+topic+'&port='+port) ws.onopen = function() {}; ws.onclose = function() {}; ws.onmessage = function(m) { addItem(JSON.parse(m.data)) }; } function addItem(obj) { $("#message").append( '<li><span class="label">'+obj.time+'</span> '+obj.msg+'</li>' ) } $(document).ready(function() { $("#submit").click(function(e) { var ip = $("#ip").val() var port = $("#port").val() var qos = $("#qos").val() var topic = $("#topic").val() mqtt(ip, port, qos, topic) }); }); </script> <form> <div class="row"> <div class="large-12 columns"> <div class="large-2 columns"> <label>Host</label> <input id="ip" type="text" name="ip" placeholder="127.0.0.1"/> </label> </div> <div class="large-2 columns"> <label>Port</label> <input id="port" type="text" name="port" placeholder="1833"/> </label> </div> <div class="large-4 columns left"> <label>Topic</label> <input id="topic" type="text" name="topic" placeholder="/sensor/temperature"/> </label> </div> <div class="large-4 columns"> <label>QoS</label> <input type="radio" id="qos" name="qos" value="0" checked><label>0</label> <input type="radio" id="qos" name="qos" value="1"><label>1</label> <input type="radio" id="qos" name="qos" value="2"><label>2</label> </label> </div> </div> <div class="large-12 columns"> <div class="large-4 columns"> <input id="submit" type="button" class="button tiny" value="연결"> </div> </div> </div> </form> <div class="row"> <div class="large-12 columns"> <div class="large-12 columns"> <div class="panel"> <ul class="no-bullet" id="message"> </ul> </div> </div> </div> </div>
# thin --threaded -R config.ru start반드시 --threaded 옵션을 이용해서 스레드 모드로 실행 해야 한다. 앞서 언급했듯이, thin은 기본적으로 EM 모드로 작동한다. 유저 요청을 비동기로 처리할 거라면, 서버의 다른 모든 입출력로 비동기 모드로 작동해야한다. 예제의 경우 mqtt.get 호출 부분에서 블럭돼 버린다. 하나의 유저만 처리할 수 있다는 이야기. 비동기 방식의 em-mqtt를 사용하면 되겠지만, 현재 버전의 루비에서는 제대로 작동을 하지 않아서, 굳이 스레드 모드로 실행 했다.
# mosquitto_pub -h 192.168.56.101 -d -t /sensor/message -m "Hello World"