From 4c267aba3fe79a9896495919e694ad4f4c379771 Mon Sep 17 00:00:00 2001 From: Daniel O'Connor Date: Tue, 3 Jun 2014 11:56:20 +0930 Subject: [PATCH] Add simple MQTT support to subscribe to, publish messages. --- Gemfile | 2 + Gemfile.lock | 2 + app/models/agents/mqtt_agent.rb | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 app/models/agents/mqtt_agent.rb diff --git a/Gemfile b/Gemfile index cf69d89d..ff6aa6d3 100644 --- a/Gemfile +++ b/Gemfile @@ -74,6 +74,8 @@ gem 'slack-notifier', '~> 0.5.0' gem 'therubyracer', '~> 0.12.1' +gem 'mqtt' + group :development do gem 'binding_of_caller' gem 'better_errors' diff --git a/Gemfile.lock b/Gemfile.lock index 4c5488db..b74c580a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -160,6 +160,7 @@ GEM mime-types (1.25.1) mini_portile (0.5.3) minitest (5.3.3) + mqtt (0.2.0) multi_json (1.9.3) multi_xml (0.5.5) multipart-post (2.0.0) @@ -341,6 +342,7 @@ DEPENDENCIES kaminari (~> 0.15.1) kramdown (~> 1.3.3) liquid (~> 2.6.1) + mqtt mysql2 (~> 0.3.15) nokogiri (~> 1.6.1) protected_attributes (~> 1.0.7) diff --git a/app/models/agents/mqtt_agent.rb b/app/models/agents/mqtt_agent.rb new file mode 100644 index 00000000..97e42786 --- /dev/null +++ b/app/models/agents/mqtt_agent.rb @@ -0,0 +1,112 @@ +# encoding: utf-8 +require "mqtt" + +module Agents + class MqttAgent < Agent + description <<-MD + The MQTT agent allows both publication to an MQTT topic and subscription to an MQTT topic. + + Setup your own broker (http://jpmens.net/2013/09/01/installing-mosquitto-on-a-raspberry-pi/) or connect to a cloud service (www.cloudmqtt.com). + + MQTT is a generic transport protocol for machine to machine communication. + + You can do things like: + + * Publish to [RabbitMQ](http://www.rabbitmq.com/mqtt.html) + * Run [OwnTracks, a location tracking tool](http://owntracks.org/) for iOS and Android + * Subscribe to your home automation setup like [Ninjablocks](http://forums.ninjablocks.com/index.php?p=/discussion/661/today-i-learned-about-mqtt/p1) or [TheThingSystem](http://thethingsystem.com/dev/supported-things.html) + + Simply choose a topic (think email subject line) to publish/listen to, and configure your service. + + Hints: + Many services run mqtts (mqtt over SSL) often with a custom certificate. + + You'll want to download their cert and install it locally, specifying the ```certificate_path``` configuration. + + + Example configuration: + +
{
+      'uri' => 'mqtts://user:pass@locahost:8883'
+      'ssl' => :TLSv1,
+      'ca_file' => './ca.pem',
+      'cert_file' => './client.crt',
+      'key_file' => './client.key',
+      'topic' => 'huginn'
+    }
+    
+ + Subscribe to CloCkWeRX's TheThingSystem instance (thethingsystem.com), where + temperature and other events are being published. + +
{
+      'uri' => 'mqtt://kcqlmkgx:sVNoccqwvXxE@m10.cloudmqtt.com:13858'
+      'topic' => 'the_thing_system/demo'
+    }
+    
+ + Subscribe to all topics +
{
+      'uri' => 'mqtt://kcqlmkgx:sVNoccqwvXxE@m10.cloudmqtt.com:13858'
+      'topic' => '/#'
+    }
+    
+ + Find out more detail on [subscription wildcards](http://www.eclipse.org/paho/files/mqttdoc/Cclient/wildcard.html) + + MD + + def validate_options + # unless options['uid'].present? && + # options['expected_update_period_in_days'].present? + # errors.add(:base, "expected_update_period_in_days and uid are required") + # end + end + + def working? + !recent_error_logs? + end + + def default_options + { + 'uri' => 'mqtts://user:pass@locahost:8883', + 'ssl' => :TLSv1, + 'ca_file' => './ca.pem', + 'cert_file' => './client.crt', + 'key_file' => './client.key', + 'topic' => 'huginn' + } + end + + def mqtt_client + client = MQTT::Client.new(options['uri']) + + if options['ssl'] + client.ssl = options['ssl'].to_sym + client.ca_file = options['ca_file'] + client.cert_file = options['cert_file'] + client.key_file = options['key_file'] + end + + client + end + + def receive(incoming_events) + mqtt_client.connect do |c| + incoming_events.each do |event| + c.publish(options['topic'], payload) + end + end + end + + + def check + mqtt_client.connect do |c| + c.get(options['topic']) do |topic,message| + create_event :payload => { 'topic' => topic, 'message' => message, 'time' => Time.now.to_i } + end + end + end + + end +end \ No newline at end of file