Visualizzazione post con etichetta ruby. Mostra tutti i post
Visualizzazione post con etichetta ruby. Mostra tutti i post

martedì 25 novembre 2014

Controllo Remoto per Caldaia - Raspberry e Client SW

Dopo aver visto come assemblare la parte HW/elettrica per il nostro  Controllo Remoto per Caldaia - HW in questo post descrivo come ho realizzato il software per il Raspberry

Architettura SW





Raspberry pi SW

Come avrete letto negli altri post sono un estimatore del pattern Publish-Subscribe e la rete PubNub lo implementa egregiamente.

Piu' nello specifico il Raspberry Pi si comporta da Subscriber in quanto ascolta il canale di comunicazione e attende la recezione di messaggi indirizzatti al Raspberri.

Al contrario i vari client (nel mio caso semplicissima web app per mobile e calendario di configurazione per PC) si comportano da Publisher in quanto inviato messaggi di comando indirizzati al Raspberry.

Tutti i messaggi sono protetti da encryption AES e sono veicolati su un canale SSL (PubNub fornisce tutti questi servizi). In aggiunta ho implemntato un semplice meccanismo di autorizzazione in modo da essere sicuro che soltanto i client autorizzati (i miei) possano pilotare la mia caldaia.

Per chi ricorda questo episodio di Big Bang Theory https://www.youtube.com/watch?v=BW9FbjjkKo4 alla fine della puntata dei ragazzi asiatici accendono e spengono le luci di Howard. Ecco noi cerchiamo di evitare questa cosa... :)


Vantaggi

Come e' ovvio altri tipi di arcitetture o meccanismi di comunicazione sono possibili.
Io ho scelto di usare PubNub in quanto:

  • PubNub fornisce un SDK praticamente per qualunque piattaforma esistente
  • Il software su Raspberry e' semplificato al massimo
  • Non devo far girare un webserver e quindi aprire una porta del mio firewall
  • Posso implementare semplicemente un mecchanismo di analytics/monitoring

Codice

Ho messo a disposizione di tutti su GitHub il codice che deve girare sul Raspberry.
Chiunque lo puo' scaricare e migliorare. 


Client SW

Per il lato client ho sviluppato 2 semplicissime applicazioni che girano su OpenShift (come avrete letto nei post precedenti sono un'utente di OpenShift molto soddisfatto - il datacenter e' Cisco UCS).


La prima e' una semplice applicazione web che mi permette di controllare lo stato della caldaia e di accenderla e spegnerla su mio comando.




Come potete vedere la veste grafica e' veramente poco attraente. Se qualcuno di voi ha capacita' grafiche si faccia avanti. Aiutera' certamente a migliorare questo progetto


La seconda e' un'applicazione legegrmente piu' complessa che va usata su PC e permette la programmazione settimanale della caldaia. Esattamente come il termostato a muro ma molto piu' flessibile.



Come vedete in figura io uso nella mia programmazione anche le informazioni relative alle valvole termostatiche applicate sul termosifone ma e' solo una visualizzazione grafica.
Cio' che accende e spegne la caldaia sono solo gli eventi "caldaia" rappresentati in verde nel mio esempio.

Ovviamente le due applicazioni sono utilizzabili parallelamente. Quindi se ho programmato l'accensione della caldaia ad un certo orario e per esempio rietro a casa con 2 ore di ritardo posso decidere di spegnere la caldaia manualmente tramite la prima app.


Il codice di entrambe le applicazioni (e' una sola applicazione Rails) e' disponibile qui SMHAC


Spero questo vi sia utile e spero che qualcuno contribuisca al miglioramento della veste grafica.

venerdì 14 novembre 2014

Quickly add delayed job to your rails app

In some of my rails app I need to have delayed/background jobs as a consequence of a controller's action call

Below quick instructions on how to add delayed jobs to any rails app:


1- add the following to Gemfile

gem 'delayed_job'
gem 'delayed_job_active_record'
gem 'daemons'


2- execute bundle install

3- create the delayed jobs tables
rails generate delayed_job:active_record

4- migrate the DB
rake db:migrate

5- in your rails root create a directory called jobs

6- add the following lines in config/application.rb
config.autoload_paths += %W(#{config.root}/jobs) #autoload delayed_jobs job
Delayed::Worker.destroy_failed_jobs = false
Delayed::Worker.sleep_delay = 60
Delayed::Worker.read_ahead = 5 #default value

7- in the jobs directory creare delayed_task.rb
DelayedTask = Struct.new(:x, :y) do

def task_worker
    begin
        res = self.x + self.y
        Rails.logger.info "Task calculating x + y = " + res.to_s
   end
end

def perform
    task_worker
end
end

8- add somewhere in your controller

Delayed::Job.enqueue(DelayedTask.new(2,3), {:priority => 0, :run_at =>  Time.now + 10.seconds})
9- start the jobs worker
rake jobs:work
or
bin/delayed_job start
10- start your raisl app and when your controller method will be called a new delayed job (DelayedTask) will be schedule and execute at the proper time

martedì 26 agosto 2014

How to hot deploy a RedHat Openshift application

Some time when you make a change to your application (in my case is a rails application) you would like to deploy the code change to your running app without restarting the cartridge on Openshift.

By default every time you perform a git push to your Openshift application, the framework execute the entire stop, build, deploy and restart activities.
This might take quite some time and your online application will not be available for few minutes.

However if you want, you can instruct Openshift to Hot Deploy your application, which means git push your code changes without restarting the application.

This will definitely reduce the downtime of your application (in most of the cases only the web server will be restarted and not the entire application cartridge like Ruby or PHP).

Enabling Hot Deploy is easy.
Add an empty hot_deploy file in the .openshift/markers directory.
Deploy this change and Openshift will understand that it should not restart the entire application when you git push your code changes


# touch .openshift/markers/hot_deploy
# git add .
# git commit -m "implementing hot deploy"
# git push


If everything is correct, next time you will push code changes to your Openshift apps, you should see something similar

remote: Not stopping cartridge ruby because hot deploy is enabled

Now your code change will be online in a quite short amount of time and especially with a very limited app downtime.

venerdì 25 luglio 2014

How easily implement PubSub in your application with PubNub

I have recently got interested in PubSub message exchange pattern.
PubSub is a great way to decouple sender and receiver and to scale to large mass of subscribers.
For networking guys, this is somehow similar to multicast. I send my IP multicat packet and I don't know who is receiving it.
In PubSub is the same, Sender app send a message which is not addressed directly to any specific receiver. On the other side Receiver listen to the communication channel without looking for a specific client.

Here I am showing very basic usage of a great service called pubnub.
The service has a free tier for developer and for testing purposed. Should you find this service the right one for your application then you can purchase service directly on pubnub web site.

Anyway, let's see how to publish (send) a message and how to subscribe (receive) a message using pubnub.
I am showing code sample in Ruby, but please note that pubnub provide API/SDK to an impressive number of platform/languages

First of all register to pubnub. You can register with you Google account or create a free account.

After successful registration you will access to a page similar to this one




Here you need to take note of two important information:

  • Subscribe Key: necessary if you want to subscribe to channels and receive messages
  • Publish Key: necessary to send message to a channel

Let's now see the code of a very simple sender and receiver


# sudo gem install pubnub
# pubnub_receive.rb

#!/usr/bin/ruby

require 'pubnub'


pubnub = Pubnub.new(
 :publish_key   => 'your publish key',
    :subscribe_key => 'your subscribekey',
    :error_callback   => lambda { |msg| puts "Error connecting to PubNub: #{msg.inspect}" },
    :connect_callback => lambda { |msg| puts "Connected to PUBNUB: #{msg.inspect}" }
 )

message_cb = lambda { |msg|
 time = Time.now
 puts "-------Received Message-------"
 puts "Channel:: #{msg.channel}"
 puts "Message:: #{msg.message}"
 puts "Message received at #{time}"
 puts "------------------------------"
}

pubnub.subscribe(
    :channel  => 'mancusoa74demo',
    :callback => message_cb
 ) 

while(1) do
 puts "."
  sleep(5)
end

Pubnub.new creates a new pubnub object and connects us to the PubNub service.
You need to specify your publish and subscribe key otherwise you will not be able to send or receive messages.

Now that we have a valid pubnub object, we can subscribe to a channel.
This is done by calling the subscribe method on pubnub object.
We need to pass (at minimum) a channel name. Here I am also specifying a callback which is executed every time we receive a message from the channel.

In the call back I simply print out the channel name, the received message and the time on which the message has been received.

As we want to listen to the channel forever I have add a simple forever loop. This is obviously not appropriate for a real implementation, but you certainly get the point of this simple example.

That's it: this is all what you need to receive message from anywhere in the world, from any device on any platform. Beauty of PubSub pattern :)


# pubnub_send.rb

#!/usr/bin/ruby

require 'pubnub'
 
pubnub = Pubnub.new(
 :publish_key   => 'your publish key',
    :subscribe_key => 'your subscribekey',
    :error_callback   => lambda { |msg| puts "Error connecting to PubNub: #{msg.inspect}" },
    :connect_callback => lambda { |msg| puts "Connected to PUBNUB: #{msg.inspect}" }
 )

pubnub.publish(
 :channel  => 'mancusoa74demo',
    :message => !ARGV[0].nil?? Time.now.to_s + " ## " + ARGV[0] : "empty message",
 ) { |data| puts "Messaage status is #{data.response_message}" }


 sleep(1)


Similarly to sender, also to receive we need to connect to PubNub network and instantiate a Pubnub object.
Unlike the receiver, to send it is not needed to subscribe to a channel.

So in order to publish/send a message we call the publish method on the pubnub object.
You need to pass the channel name and the message you want to send.

Bam!!! as simple as that. You have now sent a message to all your subscribers around the world on different devices and platform. Again beauty of PubSub pattern :)

This model/service can be used for a tons of different purposes. Example: connect with your mobile subscribers, implement a scalable chat/messaging system, implement a scalable logging system, implement a scalable analytics system, ...

In conclusion I hope it is clear from this post that communicate with your subscribers is very simple and PubNub is offering the infrastructure to support your needs.

If you have ideas or experience how to use it in your domain let me know. I am always interested to discover new things.

Cheers

Note: In this post I discuss about pubnub service. I would like to make it very clear that I have absolutely  NO affiliation with pubsub. This is just the description of my finding while looking for cool technologies out there.

giovedì 24 luglio 2014

Build a simple RESTful Web Service JSON API with Ruby and Sinatra

In one my activities I have the needs to quickly prototype a RESTful web service API.
Obviously I want to do it with my current preferred language Ruby.

It is clear I can easily do it with Rails but probably it will be an overkill for what I need to do.
Reading different articles about major differences between Rails and Sinatra micro-framework I have decided to build the simple REST web service I need using Sinatra.

I am here sharing what I have done. This is something I put together quite quickly, so it is not complete.
Anyone of you which wants to help can contribute.

Let's install the necessary ruby gems.

# cd ~
#
# mkdir rails_api
#
# mkdir rails_api/json
#
# sudo gem install sinatra
#
# sudo gem install rabl
#
# sudo gem install oj
#
# sudo gem install data_mapper
#
# sudo gem install dm-sqlite-adapter
#
# sudo gem install thin

I am using Rabl gem as this provides great flexibility in creating JSON replies to API request

Now in the rails_api/json directory create 3 files with the below content

#post.rabl
object @post
attributes :id, :title, :body

#posts.rabl
collection @posts
attributes :id, :title, :body

#error.rabl
object @error
attributes :message

Those files render the JSON replay to our RESTful API call. Now in the rails_api directory create the following file
#rest_api.rb

require 'rubygems'
require 'sinatra'
require 'rabl'
require 'data_mapper'
require 'json' 

######## setup sqlite DB ########
DataMapper.setup(:default, 'sqlite:rest_api.db')

######## Post Model ########
class Post
  include DataMapper::Resource

  property :id,         Serial    # An auto-increment integer key
  property :title,      String    # A varchar type string, for short strings
  property :body,       Text      # A text block, for longer string data.
end

DataMapper.finalize
Post.auto_upgrade!


######## Very simple Error class ########
class Error 
 attr_accessor :message
 def initialize(mex)
  @message = mex
 end
end

######## register Rabl. This is required for Sinatra ########
Rabl.register!

######## retrun 404 in case of invalid URL request ########
not_found do
 status 404 #page not found
end

######## simple helper to return HTTP 400 ########
def status_400(mex)
 @error = Error.new(mex)
 status 400
 rabl :'error', :format => "json", :views => 'json' 
end

######## simple helper to return HTTP 404 ########
def status_404(mex)
 @error = Error.new(mex)
 status 404
 rabl :'error', :format => "json", :views => 'json' 
end

######## simple helper to return HTTP 200 ########
def status_200
 status 200
end

######## simple helper to return HTTP 201 ########
def status_201(link)
 status 201
 #headers "location:/post/43"
 headers "Location"   => link
end

######## REST CRUD APIs for Post resource ########

######## index of Post ########
#GET post
get '/post' do 
 @posts = Post.all
 if @posts.empty?
  status_404("The reuqested resource does not exists")
 else
  status_200
    rabl :'posts', :format => "json", :views => 'json'
   end
end

######## show one Post ########
# GET /post/:id
get '/post/:id' do
 @post = Post.get(params[:id])
 if @post.nil?
  status_404("The reuqested resource does not exists")
 else
  status_200
    rabl :'post', :format => "json", :views => 'json'
   end
end

######## create a Post ########
#POST /post
post '/post' do
 begin
  post_data =  JSON.parse request.body.read 

  if post_data.nil? or !post_data.has_key?('title') or !post_data.has_key?('body')
   raise "exception"
  else
   post = Post.create(:title => post_data['title'], :body => post_data['body'])
   post.save
   status_201("/post/#{post.id}")
  end
 rescue => ex
  status_400("Invalid client request")
 end
end

######## Update a Post ########
#PUT /post/:id
put '/post/:id' do
 begin
  put_data =  JSON.parse request.body.read 

  if put_data.nil? or !put_data.has_key?('title') or !put_data.has_key?('body')
   raise "exception"
  else
   post = Post.get(params[:id])
   if post.nil?
    status_404("The reuqested resource does not exists")
   else
    post.title = put_data['title']
    post.body = put_data['body']
    post.save
    status_200
   end
  end
 rescue => ex
  status_400("Invalid client request")
 end

end

######## Remove a Post ########
#DELETE /post/:id
delete '/post/:id' do
 post = Post.get(params[:id])
 if post.nil?
  status_404("The reuqested resource does not exists")
 else
  post.destroy
  status_200
 end
end
Ok now just run it with
# ruby rest_api.rb -o 0.0.0.0
You should get something like this
== Sinatra/1.4.5 has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.6.2 codename Doc Brown)
Maximum connections set to 1024
Listening on 0.0.0.0:4567, CTRL+C to stop

Let's now test our RESTful Web Service. You can use your preferred tool like POSTMAN in Chrome.
I will use the always available curl to test the typical CRUD functions

CREATE

# curl -H "Content-type: application/json" -X POST  -d '{"title": "post1", "body": "this is post 1"}'  http://127.0.0.1:4567/post
READ
# curl  http://127.0.0.1:4567/post

# curl  http://127.0.0.1:4567/post/1
UPDATE
# curl -H "Content-type: application/json" -X PUT  -d '{"title": "post 5", "body": "this is post #5"}'  http://127.0.0.1:4567/post/1
DELETE
# curl -X DELETE http://127.0.0.1:4567/post/1

I am sure it is quite easy to argue that the HTTP return code I have used are not correct. Looks like this is quite an open topic.

In my example here I have mapped HTTP Status Code to REST call according to what described in this article (Using HTTP Status Codes correctly in your REST Web API)

As always let me know about any improvement, suggestion or correction.

Hope this helps someone out there.


lunedì 14 luglio 2014

How to force HTTPS on Openshift for Rails applications

RedHat OpenShift provides the possibility to enable HTTPS for your Rails application.

By default your Rails application will be available on

http://appname-domain.rhcloud.com

and

https://appname-domain.rhcloud.com

In my applications I want every request to be handled by HTTPS. In order to achieve that add to your public directory a .htaccess file with the below content


RewriteEngine on


RewriteCond %{HTTP:X-Forwarded-Proto} !https

RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R,L]


For additional information for non-Apache based applications check OpenShift article out

mercoledì 2 luglio 2014

How to delete a scheduled rails delayed_job

In one of my "experiment" I am using collectiveidea/delayed_job gem to execute background and delayed tasks/jobs.

Now the question is: how to delete a job  which has already been scheduled/queued?

As simple as that:



#schedule a delayed method call
dj = reminder.delay(run_at: 5.minutes.from_now).send #this is your delayed method object

#delete a scheduled delayed job
djid = dj.id #this is the assigned delayed_job id

Delayed::Job.delete(djid)

venerdì 13 giugno 2014

How to customize cancel button link in Active Admin for Rails

A typical form in Active Admin looks like this one
form do |f|
    f.inputs "New Post" do
      f.input :title,
      f.input :body
    end
    f.actions
end
This will give you the standard buttons: create and cancel Now in my case I need to redirect my user to a specific page when the cancel button is hit This can be achieved in this way:
form do |f|
    f.inputs "New Post" do
      f.input :title,
      f.input :body
    end
    f.actions do
      f.action(:submit) 
      f.cancel_link(admin_anothermodel_path)
    end
end
This is simple and effective way to redirect your user to the location you want