One of the advantages of using WebSockets is that a single connection is used between the server and the client and either the server or the client can send data to each other. In my case a need to send data from my sensor (that is connected to my server) to the angular client to keep the values updated.
WebSockets
Web socket is a protocol that enables communication over a single TCP connection. That means that the TCP connection stays open during all the communication between the server and the client against regular Http protocol communication where each time that the client wants to communicate with the server it needs to create a new TCP connection.
The way that the WebSockets work is by upgrading the connection, this process is known as WebSocket handshake and it is done by starting a regular Http request to a server but with an Upgrade header included in the request.
Client Request Http Heather:
GET / HTTP/1.1 Host: 192.168.43.135:12345 Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: file:// Sec-WebSocket-Version: 13 User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Accept-Encoding: gzip, deflate, sdch Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Key: bKdPyn3u98cTfZJSh4TNeQ==
If the server supports WebSocket protocol this will send a response including an Upgrade heather that indicating that the WebSocket communication will take place. Now a single TCP/IP connection has established and either party can starting to send data.
Flask and Flask-SocketIO
We are going to use Flask because I am using python to read the information that is being sent to my beagle bone module. (Although you can easy change everything to NodeJs) Flask is a micro web framework that allows you to create REST APIs. Flask-SocketIO allows Flask application to create WebSocket communication with any client-side application that uses the SocketIO javascript library as our Angular app is.
Installation We need to install python3 and we are going to use virtual-env to maintain a separate environment for this project.
sudo apt install python3 apt install python3-venv
python3 -m venv flaskenv
Now go inside the virtual-environment and install Flask and Flask-SocketIO.
source /flaskenv/bin/activate pip install flask pip install flask-restful
pip install flask flask-socketio
Server
The next script is the Server.py is a single file that we are going to use for running the application inside the beagle bone.
Server.py
from flask import Flask, jsonify, render_template from flask_restful import Resource, Api, marshal_with from flask_socketio import SocketIO,emit,send import bbbserial as bbb from threading import Thread import time #First we create call the Flask framework and create a secret password. #Then create socketio variable where cors_allowed_origin = * to acept communication with other domains. app = Flask(__name__) app.config['SECRET_KEY'] = 'secret!' socketio = SocketIO(app, cors_allowed_origins='*') thread = None clients = 0 #Function that calls the BeagleBone class that is in charged of reading the temperature sensor def ini_socket(): global clients,thread b = bbb.Beagle() while clients > 0: print('Sending data from WebSocket, numClientes: {0}'.format(clients)) b.GetTemperature() print('sending Data: temp: {0}, hum: {1}'.format(b.temperature,b.humidity)) socketio.emit('data-tmp', {'temperature': b.temperature, 'humedity':b.humidity}) time.sleep(1) thread = None #we restore the thread so it can be used again #This is the api that we can run by calling http://ip:5000/api/socket #this API is called from the Angular client and it creates a separate thread from the main thread #and executess the function ini_socket. @app.route('/api/socket') def index(): print('Route socket init') global thread if thread is None: thread = Thread(target=ini_socket) thread.start() return ('{"ok":"success"}') #Function that runs when a clients get connected to the server @socketio.on('connect') def test_connect(): global clients clients += 1 print('Client connected test') #Read data from client @socketio.on('new-message') def handle_message(message): print('received message' + message) send_data() #Send data to client @socketio.on('new-message-s') def send_data(): b = bbb.Beagle() b.GetTemperature() print('sending Data: temp: {0}, hum: {1}'.format(b.temperature,b.humidity)) emit('data-tmp', {'temperature': b.temperature, 'humedity':b.humidity}) @socketio.on('disconnect') def test_disconnect(): global clients clients -= 1 print('Client disconnected') #This is the function that will create the Server in the ip host and port 5000 if __name__ == "__main__": print("starting webservice")</pre> <pre spellcheck="false">Angular
In Angular, we have to use Socket.IO. To install the Socket.IO library we type the next commands.
npm i socket.io-client --savenpm i @types/socket.io-client --save Angular project structureCreate SocketService and don´t forget to import the SocketService in the app.module
This service will call the API in the server to initialize the temperature reading.
import { Injectable } from '@angular/core'; import * as io from 'socket.io-client'; import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class SocketService { private socket: SocketIOClient.Socket; private messages: Array<any>; constructor(private http: HttpClient) {} public iniServerSocket(){ this.http.get('http://10.42.0.19:5000/api/socket') .subscribe(data => { console.log(data); }) }
}
Create a new component Temperature.component.ts
On init, the component will call 3 functions.
The connect function will stablish the socket connection with the server, the second function will stablish the communication channel where the client is going to be receiving data from the server and the third function the client will call an API in the server to initialize the process of reading the sensor.
The getTempColor will change the color in the angular client depending on the temperature.
import { Component, OnInit, Input } from '@angular/core'; import { SocketService } from '../_sevices/socket.service'; import * as io from 'socket.io-client'; @Component({ selector: 'app-temperature', templateUrl: './temperature.component.html', styleUrls: ['./temperature.component.css'] }) export class TemperatureComponent implements OnInit { private socketio: SocketIOClient.Socket; public temperature: string; public humidity: string; @Input() color: string; constructor(private socket: SocketService) { } ngOnInit() { this.connect(); this.setReceiveMethod(); this.socket.iniServerSocket(); } connect(){ this.socketio = io('http://10.42.0.19:5000'); } setReceiveMethod() { this.socketio.on('data-tmp', (data) => { console.log(data); this.temperature = data.temperature + '°C'; this.humidity = data.humedity; this.color = this.getTempColor(data.temperature); }); } sendmessage() { this.socketio.emit('new-message', 'Hi-flask'); } getTempColor(temperature: number) { if (temperature < 10 ) { return '#334FFF'; } else if (temperature >= 10 && temperature < 18) { return '#33BDFF'; } else if (temperature >= 18 && temperature < 25) { return '#4CFF33'; } else if (temperature >= 25 && temperature < 32) { return '#FFA533'; } else if (temperature >= 32) { return '#F90000'; } }
} The results.
In green we can see what the sensor is reading, we are using the serial terminal of Arduino to read the data.
In orange, we can are connected to the server using SSH and we are running the socket server that we build with python.
Receiving data from the server to the Angular client
In the next image, we can see that the Angular client running and it is receiving the data from the server. So we don’t need to be requesting data each time to refresh the information.
Then I add some fire to the sensor to increase the temperature
As soon the server gets the temperature from the sensor it sends that to the Angular client through the socket that they established.
The code in github/matvi
hi thanks for the tutorial but i have a question did you use raspberry pi as a server?
LikeLike
I used a card called Beagle bone black. But you should be able to adapt it to the Raspberry Pi
LikeLike
aaa i get it but can you help me please?can i connect the sensors to my raspberrypi and send the data to my angular js project using websocket?and do i install the command apt install python3-venv in my raspberry pi terminal?thanks in advance
LikeLike
Hi Amal.
Yes, you can connect sensors to your Raspberry Pi.
In order to complete your project, you need to divide the problem into sections.
First, you need to think about how to send the data. I used one sensor connected to the Arduino and I was sending the information wirelessly to my server using Zeegbee.
Then you need to think about how to set up the client project (Angular) with the server (flask).
You can adapt everything to use a different card. I used beagle-bone but you can use Raspberry, both have a version of Linux.
The only difference is the code that will communicate with the sensors, which will change but should be easy to investigate on your part.
Just remember to divide and conquer.
LikeLike
thanks for your reply you really helped me, but i have a question i have created a server in my raspberry pi pretty much like yours and i didn’t create a client yet the problem is when i type sudo python3 server.py nothing happens i don’t get errors and i don’t get any message i really don’t understand i tried to test it before creating the client,and thanks in advance
LikeLike
Hey Amal. Send me a message to my LinkedIn https://www.linkedin.com/in/davidmataviejo/
LikeLike
sorry I couldn’t msg you on LinkedIn
LikeLike
You need to open an account and add me as a contact
LikeLike
I have connected you ,waiting for you to accept me thanks
LikeLike