How to access data in outside function from inside function? - python

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()

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!

Python multithread and share class object

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?

How to make android app as server and python as client side

Description
So basically i am building an android app in which i am using kotlin and which will behave as server.Whilst on the client side i am using python.I am using sockets for this purpose.I have to communicate using UDP.But i am unable to make connection to my android app.In python script sock.connect(('10.0.2.2', 6000)) i have also tried placing the emulator ip instead of localhost.I just want to send and receive simple messages.
Another Issue: Python script just times out it does not even gets into the loop.
Server.kt
package com.example.soundsource
import android.content.Intent
import android.os.AsyncTask
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import java.io.BufferedInputStream
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.PrintWriter
import java.lang.Exception
import java.lang.ref.WeakReference
import java.net.ServerSocket
import java.net.Socket
class MainActivity : AppCompatActivity() {
private lateinit var textView:TextView
private var message = " "
private lateinit var client:Socket
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val sendButton:Button = findViewById(R.id.send_button)
val showLocation = findViewById(R.id.show_location) as? Button
showLocation?.setOnClickListener {
val intent = Intent(this,SoundLocation::class.java)
startActivity(intent)
}
textView = findViewById(R.id.text_view)
sendButton.setOnClickListener{
t.start()
}
}
private val t = Thread(Runnable {
val port = 5000
val server = ServerSocket(port)
this.message = "Message from client"
this#MainActivity.runOnUiThread {
this.textView.text = server.localPort.toString()
}
val i = InputStreamReader(this.client.getInputStream())
val b = BufferedReader(i)
while (true){
this.client = server.accept()
message += " "+ this.client.localAddress.toString()+b.readLine()
this#MainActivity.runOnUiThread{
this.textView.text = server.localSocketAddress.toString()
}
t2.start()
}
})
private val t2 = Thread(Runnable {
val p = PrintWriter(this.client.getOutputStream())
p.println("sending message back")
runOnUiThread {
this.textView.text = "message sent...."
}
})
}
Client.py
import socket
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('10.0.2.2', 5000))
while True:
print("you are about to.....")
data = sock.recv(1024)
print('you received :', data)
sock.sendall(bytes("hey kotlin....", 'utf-8'))
main()

python mqtt-paho disconnect after publish

I am trying to publish single message to MQTT and disconnect with following code. But it works sometime, sometime doesn't work as expected. I want to listen for a topic for if the switch1 os on then turn off, of its of then turn on based on the received data and disconnect.
#!/usr/bin/env python2.7
import json
import time
import os
import paho.mqtt.client as mqtt
mqtt_host = os.getenv('HOST', 'xxxx')
mqtt_port = os.getenv('PORT', 1883)
mqtt_username = os.getenv('USERNAME', 'xxxx')
mqtt_password = os.getenv('PASSWORD', 'xxxx')
mqtt_subacribe_topic = os.getenv('SUBSCRIBE_TOPIC', 'xxxx')
mqtt_publish_topic = os.getenv('PUBLISH_TOPIC', 'xxxx')
sleep_time = os.getenv('SLEEP_TIME', 15)
CLIENT_ID = "lambda"
SWITCH1_ON = { "SWITCH1": "on" }
SWITCH1_OFF = { "SWITCH1": "off" }
def on_publish(client, userdata, mid):
print ("Message Published...")
client.disconnect()
def on_subscribe(client, userdata, mid, granted_qos):
print("Subscribed: " + str(message.topic) + " " + str(mid) + " " + str(granted_qos))
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to broker")
client.subscribe(mqtt_subacribe_topic)
else:
print("Connection failed")
def on_message(client, userdata, msg):
payload = json.loads(msg.payload)
if payload.get('switch1') == 1:
client.publish(mqtt_publish_topic,json.dumps(SWITCH1_ON))
elif payload.get('switch1') == 0:
client.publish(mqtt_publish_topic,json.dumps(SWITCH1_OFF))
def main():
client = mqtt.Client(CLIENT_ID)
client.username_pw_set(mqtt_username, password=mqtt_password)
# Register publish callback function
client.on_publish = on_publish
client.on_connect = on_connect
client.on_message = on_message
# Connect with MQTT Broker
client.connect(mqtt_host, port=mqtt_port)
# Loop forever
client.loop_start()
time.sleep(sleep_time)
client.loop_stop()
client.disconnect()
if __name__ == "__main__":
main()
Based on hardillb's answer I tried :
#!/usr/bin/env python2.7
import json
import time
import os
import paho.mqtt.subscribe as subscribe
import paho.mqtt.publish as publish
mqtt_host = os.getenv('HOST', 'xxx.cloudmqtt.com')
mqtt_port = os.getenv('PORT', 1883)
mqtt_username = os.getenv('USERNAME', 'xxx')
mqtt_password = os.getenv('PASSWORD', 'xxx')
mqtt_subacribe_topic = os.getenv('SUBSCRIBE_TOPIC', 'xxx')
mqtt_publish_topic = os.getenv('PUBLISH_TOPIC', 'xxx')
sleep_time = os.getenv('SLEEP_TIME', 14)
CLIENT_ID = "lambda"
SWITCH1_ON = { "SWITCH1": "on" }
SWITCH1_OFF = { "SWITCH1": "off" }
auth = {'username':mqtt_username, 'password':mqtt_password}
def on_message(client, userdata, msg):
payload = json.loads(msg.payload)
print(payload)
if payload.get('switch1') == 1:
publish.single(mqtt_publish_topic,json.dumps(SWITCH1_ON),hostname=mqtt_host,auth=auth)
print "Turning switch1 ON"
elif payload.get('switch1') == 0:
publish.single(mqtt_publish_topic,json.dumps(SWITCH1_OFF),hostname=mqtt_host,auth=auth)
print "Turning switch1 OFF"
def main():
subscribe.callback(on_message, mqtt_subacribe_topic,hostname=mqtt_host,auth=auth)
if __name__ == "__main__":
main()
But script is keep running, I have to kill it to stop. Is it possible to just subscribed to a topic and once first message is received, process it, publish to another topic and end the execution.
If you just want to publish a single message then the Paho client has a built in method to do this. You can find the doc here
import paho.mqtt.publish as publish
publish.single("paho/test/single", "payload", hostname="iot.eclipse.org")
There is an equivalent method for also subscribing to a topic and receiving a single message.

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