How to communicate with IoT device from webhook using rails - ruby

I am learning Google Home Integration with IoT device. I have IoT device which reponds only TCP/WS protocol to get/update things in the device. I am running webhook in rails application. Rails web service can get request from google assistant and respond back. Now to fullfill the request received from google assistant, I have to make TCP/WS request to the device. I am running client web socket program in the device to get request. server web socket program is in server side. my problem (same) is how to forward received request from google assistant to the device using web socket and get response from device and forward to google assistant.
Here is sample controller code.
class WebhookController < ApplicationController
def create
value = params[:result][:parameters][:value].first
action = params[:result][:parameters]['action'].first
/*
Here I have to access the following web socket connection and send the request and need to get response back and update to google assistant.
*/
res = { 'speech' => "temperature #{value} successfully changed.", 'displayText' => 'success' }
render json: res
end
end
Sample web socket server which is already connected with client which is running in the device.
require 'em-websocket'
EM.run {
EM::WebSocket.run(:host => "0.0.0.0", :port => 8080) do |ws|
ws.onopen { |handshake|
puts "WebSocket connection open"
ws.send "Hello Client, you connected to #{handshake.path}"
}
ws.onclose { puts "Connection closed" }
ws.onmessage { |msg|
puts "Recieved message: #{msg}"
ws.send msg
/*
Here It should get msg from controller and forward to the client and get response from client and send to server controller.
*/
}
end
}

Related

How to return from a Rails rack call?

I am using Faye websocket implementation. When a websocket is detected I want to make sure the user sent a given header before I open the connection, or else I want to return an error.
I tried returning error 401 using [] but I keep oberving that the code continues execution and the websocket is created anyway. I managed to prevent it by adding return after it, but I am not sure this is the right way. On the client side I am implementing it in python using ws4py and when I return I get an exception raised indicating it received a 302 code, not the 401 I was expecting to send.
My ruby code (without the websocket events code) follows:
App = lambda do |env|
if Faye::WebSocket.websocket?(env)
unless env['HTTP_MY_HEADER']
[401, {'Content-Type' => 'application/json'}, '{"message": "I was expecting a header here"}']
#return (??)
end
ws = Faye::WebSocket.new(env)
# Rest of websocket call handling
else
# Normal HTTP request
[200, {'Content-Type' => 'text/plain'}, ['Hello']]
end
end

Ruby: Make a call from browser using Twilio

I want to call from my browser to customer phone number using Twilio. I am using toturial of Twilio. I have already an account that I am using for sending sms to my users. Now I want to make phone calls too. This is the code that I am using at my controller
account_sid = "My Twilio account SID"
auth_token = "My Twilio auth"
sender = "My Twilio from number"
capability = Twilio::Util::Capability.new account_sid, auth_token
capability.allow_client_outgoing "My Twilio Twiml app sid"
#capability.allow_client_incoming "jenny"
#token = capability.generate
And this is the javascript code
Twilio.Device.setup("<%= #token %>", {debug: true});
Twilio.Device.ready(function (device) {
$("#log").text("Ready");
});
Twilio.Device.error(function (error) {
$("#log").text("Error: " + error.message);
});
Twilio.Device.connect(function (conn) {
$("#log").text("Successfully established call");
});
Twilio.Device.disconnect(function (conn) {
$("#log").text("Call ended");
});
Twilio.Device.incoming(function (conn) {
$("#log").text("Incoming connection from " + conn.parameters.From);
// accept the incoming connection and start two-way audio
conn.accept();
});
function call() {
// get the phone number to connect the call to
params = {"PhoneNumber": $("#number").val()};
Twilio.Device.connect(params);
}
function hangup() {
Twilio.Device.disconnectAll();
}
But when I try to load my page, it gives me Error: No valid account. I have double checked my credentials and same credentials are successfully sending sms but here it is creating problem. Can any one guide me what Am I doing wrong?
I am doing it on localhost
Megan from Twilio here. You mention you're on localhost. You would need to make your URL publicly accessible. If you're not ready for production, testing with something like Ngrok will allow you to tunnel your localhost to a publicly available URL.

em-websocket and javascript client connection

I've got a simple eventmachine web socket server (eventmachine 1.0.0):
EM.run {
# WebSocket Server
EM::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
ws.onopen do
sid = #channel.subscribe{|msg| ws.send msg }
puts "* new WebSocket client <#{sid}> connected!"
end
ws.onmessage do |msg|
puts "* websocket client <#{#sid}> : #{msg}"
end
ws.onclose do
#channel.unsubscribe(sid)
puts "* websocket client <#{#sid}> closed"
end
end
}
I'm trying to connect to it through a javascript client with the following code:
socket = new WebSocket("ws://localhost:8080");
socket.onopen = function(e) {
socket.send('Connesso');
};
socket.onmessage = function(mess) {
if (mess) {
socket.send(mess);
}
};
socket.onclose = function(e) {
socket.send('Disconnesso');
};
With previous versions of safari it was working flawlessly with the latest one the client is not connecting to the server.
I tried it also with last Chrome Dev stable version but it's not working.
The web socket header is sent but it remains in pending status.
If I send a text message to the web socket I receive the INVALID_STATE_ERR: DOM Exception 11.
I saw that there has been a draft change but I thought em-websocket 0.3.8 already implemented it.
Can you help me solve this issue?
Thanks a lot
INVALID_STATE_ERR: DOM Exception 11 means your websocket is not in ready state yet.
you can check state of websocket object by socket.readyState
you are able to send messages when socket.readyState == 1
I created a turnaround for this by using timeout
timerId = setInterval(sendDataWhenReady, 1000);
function sendDataWhenReady(){
if(socket.readyState == 1){
ws.send(JSON.stringify({"type": 'STATUS', "status": status, "username": logged_in_user}))
clearInterval(timerId);
}
}

WebSockets: How to notify all subscribers when a client connection has dropped?

I have a little WebSocket chat demo that I am working on (based on this code). However, the part that doesn't seem to be working is when a connection is closed between a client and the server, I want to notify all the subscribers that the user has "left the chatroom". I thought that the server would be notified/run the onclose function when the client connection was dropped, but maybe that's not how WebSockets work.
Here's my EventMachine code:
ws.onclose do
puts "Connection closed"
ws.send ({:type => 'status', :message => "#{#subscribers[subscriber_id]} has left the chatroom"}.to_json)
#main_channel.unsubscribe(subscriber_id)
end
You are trying to send data to a WebSocket that was just closed, that won't work. You probably want to just push a message to the Queue like:
ws.onclose do
puts "Connection closed"
msg = {:type => 'status', :message => "#{#subscribers[subscriber_id]} has left the chatroom"}.to_json
#main_channel.push(msg)
#main_channel.unsubscribe(subscriber_id)
end
That way the message will be send to all subscribers.
Best regards
Tobias

socket.io and eventmachine in ruby

I am trying out a very basic server/client demo. I am using socket.io on the client(a user in a browser) and eventmachine Echo example for server. Ideally socket.io should send a request to server and server will print the received data. Unfortunately, something is not working as I expect it to.
Source is pasted here:
socket = new io.Socket('localhost',{
port: 8080
});
socket.connect();
$(function(){
var textBox = $('.chat');
textBox.parent().submit(function(){
if(textBox.val() != "") {
//send message to chat server
socket.send(textBox.val());
textBox.val('');
return false;
}
});
socket.on('message', function(data){
console.log(data);
$('#text').append(data);
});
});
and here is ruby code:
require 'rubygems'
require 'eventmachine'
require 'evma_httpserver'
class Echo < EM::Connection
def receive_data(data)
send_data(data)
end
end
EM.run do
EM.start_server '0.0.0.0', 8080, Echo
end
You client code is trying to connect to a server using the websockets protocol. However, your server code isn't accepting websockets connections - it's only doing HTTP.
One option is to use the event machine websockets plugin:
https://github.com/igrigorik/em-websocket
EventMachine.run {
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8080) do |ws|
ws.onopen {
puts "WebSocket connection open"
# publish message to the client
ws.send "Hello Client"
}
ws.onclose { puts "Connection closed" }
ws.onmessage { |msg|
puts "Recieved message: #{msg}"
ws.send "Pong: #{msg}"
}
end
}
I'd look into using Cramp. It's an async framework with websockets support, built on top of EventMachine. I've played around with the samples and I have to admit that the API looks elegant and clean.
I would look into Plezi.
Your server side echo code could look something like this:
require 'plezi'
class EchoCtrl
def index
redirect_to 'http://www.websocket.org/echo.html'
end
def on_message data
# to broadcast the data add:
# broadcast :_send_message, data
_send_message data
end
def _send_message data
response << data
end
end
listen
# you can add, a socket.io route for JSON with socket.io
route '/socket.io', EchoCtrl
route '/', EchoCtrl
just type it in IRB and the echo server will start running once you exit IRB using the exit command.
Plezi is really fun to work with and support Websockets, HTTP Streaming and RESTful HTTP requests, so it's easy to fall back on long-pulling and serve static content as well as real-time updates.
Plezi also has built in support for Redis, so it's possible to push data across processes and machines.

Resources