I'm trying to use Paho MQTT Client and Multiprocessing to send temperature with defined interval. However, publish command is not working inside class. I've checked self.mqtt_client inside scheduler it has the Client object.
Is there anyone that can address problem for me?
Everything inside class is working except Scheduler.
def scheduler(self, topic, interval):
if interval != 0:
while True:
if topic == "temp":
print("Temperature published " + interval) #It's working.
self.mqtt_client.publish(topic, interval , 0 , False) #There is no error/output about this line
time.sleep(int(interval))
else:
pass
Class:
class Switcher:
config = None
mqtt_client = None
mqtt_connected = False
switches = {}
stages = {}
def __init__(self, config):
self.config = config
for switch_cfg in self.config['switches']:
self.switches[switch_cfg['topic_set']] = Switch(int(switch_cfg['gpio']), switch_cfg['topic_status'], switch_cfg['initial'])
def scheduler(self, topic, interval):
if interval != 0:
while True:
if topic == "temp":
print("Temperature published " + interval) #It's working.
self.mqtt_client.publish(topic, interval , 0 , False) #There is no error/output about this line
time.sleep(int(interval))
else:
pass
def mqtt_connect(self):
if self.mqtt_broker_reachable():
self.verbose('Connecting to ' + self.config['mqtt_host'] + ':' + self.config['mqtt_port'])
self.mqtt_client = mqtt.Client(self.config['mqtt_client_id'])
if 'mqtt_user' in self.config and 'mqtt_password' in self.config:
self.mqtt_client.username_pw_set(self.config['mqtt_user'], self.config['mqtt_password'])
self.mqtt_client.on_connect = self.mqtt_on_connect
self.mqtt_client.on_disconnect = self.mqtt_on_disconnect
self.mqtt_client.on_message = self.mqtt_on_message
try:
self.mqtt_client.connect(self.config['mqtt_host'], int(self.config['mqtt_port']), 10)
for switch_cfg in self.config['switches']:
self.mqtt_client.subscribe(switch_cfg['topic_set'], 0)
self.mqtt_client.loop_forever()
except:
self.error(traceback.format_exc())
self.mqtt_client = None
else:
self.error(self.config['mqtt_host'] + ':' + self.config['mqtt_port'] + ' not reachable!')
def mqtt_on_connect(self, mqtt_client, userdata, flags, rc):
self.mqtt_connected = True
for switch_ios in self.config['switches']:
self.mqtt_client.publish(self.config['station_status'], "available", 0, False)
self.mqtt_client.publish(switch_ios['topic_status'], self.switches[switch_ios['topic_set']].get_state(), 0, False)
temp_interval = 1
temp_process = multiprocessing.Process(target=self.scheduler, args=("temp",str(temp_interval),))
temp_process.start()
self.verbose('...mqtt_connected!')
def mqtt_broker_reachable(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
try:
s.connect((self.config['mqtt_host'], int(self.config['mqtt_port'])))
s.close()
return True
except socket.error:
return False
def start(self):
self.mqtt_connect()
You mqtt_connect function will never return.
self.mqtt_client.loop_forever() Will block until self.mqtt_client.disconnect() is called.
You should probably be using self.mqtt_client.loop_start() which will run the client loop on it's own thread in the background. You can call self.mqtt_client.loop_stop() when you want to shut the client down.
Related
I am creating an app where the server and clients run on the same machine, see picture.
I want the user to be able to send data from the server to a specific client (= specific window). For this, the user needs to know which ID belongs to which client (for example the corresponding ID could be displayed in each window's title).
Is it possible to get the corresponding descriptor ID on the client side? If not, how could I achieve the same result anyway?
I expect something like this as a result:
Here is an example code in pyside2 but I don't mind if the solution is using C++ qt.
QTCPServer:
import sys
from typing import List
from PySide2.QtCore import *
from PySide2.QtNetwork import *
from PySide2.QtWidgets import *
class MainWindow(QMainWindow):
new_message = Signal(bytes)
_connection_set: List[QTcpSocket] = []
def __init__(self):
super().__init__()
self.server = QTcpServer()
# layout
self.setWindowTitle("QTCPServer")
self._central_widget = QWidget()
self._main_layout = QVBoxLayout()
self.status_bar = QStatusBar()
self.text_browser_received_messages = QTextBrowser()
self._controller_layout = QHBoxLayout()
self.combobox_receiver = QComboBox()
self.lineEdit_message = QLineEdit()
self._controller_layout.addWidget(self.combobox_receiver)
self._controller_layout.addWidget(self.lineEdit_message)
self._buttons_layout = QHBoxLayout()
self.send_message_button = QPushButton("Send Message")
self.send_message_button.clicked.connect(self.send_message_button_clicked)
self._buttons_layout.addWidget(self.send_message_button)
# end layout
if self.server.listen(QHostAddress.Any, 8080):
self.new_message.connect(self.display_message)
self.server.newConnection.connect(self.new_connection)
self.status_bar.showMessage("Server is listening...")
else:
QMessageBox.critical(self, "QTCPServer", f"Unable to start the server: {self.server.errorString()}.")
self.server.close()
self.server.deleteLater()
sys.exit()
# set layout
self.setStatusBar(self.status_bar)
self.setCentralWidget(self._central_widget)
self._central_widget.setLayout(self._main_layout)
self._main_layout.addWidget(self.text_browser_received_messages)
self._main_layout.addLayout(self._controller_layout)
self._main_layout.addLayout(self._buttons_layout)
def new_connection(self) -> None:
while self.server.hasPendingConnections():
self.append_to_socket_list(self.server.nextPendingConnection())
def append_to_socket_list(self, socket: QTcpSocket):
self._connection_set.insert(len(self._connection_set), socket)
self.connect(socket, SIGNAL("readyRead()"), self.read_socket)
self.connect(socket, SIGNAL("disconnected()"), self.discard_socket)
self.combobox_receiver.addItem(str(socket.socketDescriptor()))
self.display_message(f"INFO :: Client with socket:{socket.socketDescriptor()} has just entered the room")
def read_socket(self):
socket: QTcpSocket = self.sender()
buffer = QByteArray()
socket_stream = QDataStream(socket)
socket_stream.setVersion(QDataStream.Qt_5_15)
socket_stream.startTransaction()
socket_stream >> buffer
if not socket_stream.commitTransaction():
message = f"{socket.socketDescriptor()} :: Waiting for more data to come.."
self.new_message.emit(message)
return
header = buffer.mid(0, 128)
file_type = header.split(",")[0].split(":")[1]
buffer = buffer.mid(128)
if file_type == "message":
message = f"{socket.socketDescriptor()} :: {str(buffer, 'utf-8')}"
self.new_message.emit(message)
def discard_socket(self):
socket: QTcpSocket = self.sender()
it = self._connection_set.index(socket)
if it != len(self._connection_set):
self.display_message(f"INFO :: A client has just left the room")
del self._connection_set[it]
socket.deleteLater()
self.refresh_combobox()
def send_message_button_clicked(self):
receiver = self.combobox_receiver.currentText()
if receiver == "Broadcast":
for socket in self._connection_set:
self.send_message(socket)
else:
for socket in self._connection_set:
if socket.socketDescriptor() == int(receiver):
self.send_message(socket)
return
self.lineEdit_message.clear()
def send_message(self, socket: QTcpSocket):
if not socket:
QMessageBox.critical(self, "QTCPServer", "Not connected")
return
if not socket.isOpen():
QMessageBox.critical(self, "QTCPServer", "Socket doesn't seem to be opened")
return
string = self.lineEdit_message.text()
socket_stream = QDataStream(socket)
socket_stream.setVersion(QDataStream.Qt_5_15)
header = QByteArray()
string_size = len(string.encode('utf-8'))
fstring = f"fileType:message,fileName:null,fileSize:{string_size}"
header.prepend(fstring.encode())
header.resize(128)
byte_array = QByteArray(string.encode())
byte_array.prepend(header)
socket_stream.setVersion(QDataStream.Qt_5_15)
socket_stream << byte_array
def display_message(self, string):
self.text_browser_received_messages.append(string)
def refresh_combobox(self):
self.combobox_receiver.clear()
self.combobox_receiver.addItem("Broadcast")
for socket in self._connection_set:
self.combobox_receiver.addItem(str(socket.socketDescriptor()))
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
QTCPClient
import sys
from PySide2.QtCore import *
from PySide2.QtNetwork import *
from PySide2.QtWidgets import *
class MainWindow(QMainWindow):
new_message = Signal(bytes)
def __init__(self):
super().__init__()
self.socket = QTcpSocket(self)
# layout
self.setWindowTitle("QTCPClient")
self._central_widget = QWidget()
self._main_layout = QVBoxLayout()
self.status_bar = QStatusBar()
self.text_browser_received_messages = QTextBrowser()
self._controller_layout = QHBoxLayout()
self.lineEdit_message = QLineEdit()
self._controller_layout.addWidget(self.lineEdit_message)
self._buttons_layout = QHBoxLayout()
self.send_message_button = QPushButton("Send Message")
self.send_message_button.clicked.connect(self.on_send_message_button_clicked)
self._buttons_layout.addWidget(self.send_message_button)
# end layout
self.new_message.connect(self.display_message)
self.connect(self.socket, SIGNAL("readyRead()"), self.read_socket)
self.connect(self.socket, SIGNAL("disconnected()"), self.discard_socket)
# set layout
self.setStatusBar(self.status_bar)
self.setCentralWidget(self._central_widget)
self._central_widget.setLayout(self._main_layout)
self._main_layout.addWidget(self.text_browser_received_messages)
self._main_layout.addLayout(self._controller_layout)
self._main_layout.addLayout(self._buttons_layout)
self.socket.connectToHost(QHostAddress.LocalHost, 8080)
if self.socket.waitForConnected():
self.status_bar.showMessage("Connected to Server")
else:
QMessageBox.critical(self, "QTCPClient", f"The following error occurred: {self.socket.errorString()}.")
if self.socket.isOpen():
self.socket.close()
sys.exit()
def discard_socket(self):
self.socket.deleteLater()
self.socket = None
self.status_bar.showMessage("Disconnected!")
def read_socket(self):
buffer = QByteArray()
socket_stream = QDataStream(self.socket)
socket_stream.setVersion(QDataStream.Qt_5_15)
socket_stream.startTransaction()
socket_stream >> buffer
if not socket_stream.commitTransaction():
message = f"{self.socket.socketDescriptor()} :: Waiting for more data to come.."
self.new_message.emit(message)
return
header = buffer.mid(0, 128)
file_type = header.split(",")[0].split(":")[1]
buffer = buffer.mid(128)
if file_type == "message":
message = f"{self.socket.socketDescriptor()} :: {str(buffer, 'utf-8')}"
self.new_message.emit(message)
def on_send_message_button_clicked(self):
if not self.socket:
QMessageBox.critical(self, "QTCPServer", "Not connected")
return
if not self.socket.isOpen():
QMessageBox.critical(self, "QTCPServer", "Socket doesn't seem to be opened")
return
string = self.lineEdit_message.text()
socket_stream = QDataStream(self.socket)
socket_stream.setVersion(QDataStream.Qt_5_15)
header = QByteArray()
string_size = len(string.encode('utf-8'))
fstring = f"fileType:message,fileName:null,fileSize:{string_size}"
header.prepend(fstring.encode())
header.resize(128)
byte_array = QByteArray(string.encode())
byte_array.prepend(header)
socket_stream << byte_array
self.lineEdit_message.clear()
def display_message(self, string: str):
self.text_browser_received_messages.append(string)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The socket descriptors are only valid for the constructor and they do not match on both sides.
One possibility is to automatically send a first "handshake" message to the client as soon as it's connected, the client will identify that message as a "descriptor id" type, and eventually set its window title.
In the following changes to your code, I'm using a simple fileType:descriptor header, and the descriptor id is actually sent as an integer value into the datastream. You can obviously use a string there, if you want to send any other value.
# server
def append_to_socket_list(self, socket: QTcpSocket):
# ...
descriptor = int(socket.socketDescriptor())
socket_stream = QDataStream(socket)
fstring = 'fileType:descriptor,fileName:null,fileSize:{},'.format(descriptor.bit_length())
header = QByteArray()
header.prepend(fstring.encode())
header.resize(128)
socket_stream << header
socket_stream.writeInt32(descriptor)
# client
def read_socket(self):
# ...
header = buffer.mid(0, 128)
fields = header.split(",")
file_type = fields[0].split(":")[1]
buffer = buffer.mid(128)
if file_type == "descriptor":
self.id = socket_stream.readInt32()
self.setWindowTitle("QTCPClient - id {}".format(self.id))
Some suggestions:
both signals have a bytes signature, but this is wrong as you're emitting those signals as str types; if you're not sure, you can use the basic object type;
the self.connect syntax is considered obsolete, use the "new" (well, not so new anymore) style one: object.signal.connect(slot); for instance:
self.socket.readyRead.connect(self.read_socket)
use QApplication.quit() instead of sys.exit(), so that the application properly does everything it needs before actually quitting the python interpreter;
instead of using the text value of the combo, you should use the user data:
descriptor = socket.socketDescriptor()
self.combobox_receiver.addItem(str(descriptor), descriptor)
then you can access it by using self.combobox_receiver.currentData() (you can add the "broadcast" item with a -1 value); you could even add the socket itself as user data;
to properly split the header without getting garbled results for the last field, you must add a final comma, otherwise split() will return the whole rest of the string;
Note for PyQt users: socketDescriptor() returns a sip.voidptr, to obtain the actual value use int(socket.socketDescriptor()).
Hello software developers.
I am new in programming and ROS. I am working now with servo motors and want to make the controlling node to rotate motor into some degrees like from 0 --> 90--> 180-->0 degrees.
there is a main code and I would like to add def function into the main node:
#!/usr/bin/env python
import os
import rospy
from std_msgs.msg import String
from controller_motor.msg import Motor
from controller_motor.srv import Motor2
if os.name == 'nt':
import msvcrt
def getch():
return msvcrt.getch().decode()
else:
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
def getch():
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
from dynamixel_sdk import * # Uses Dynamixel SDK library
class DynamixelController(object):
def __init__(self):
#print("1")
self.motor_sub = rospy.Subscriber("/motor_topic", Motor, self.motor_callback)
self.test_motor_client(1) #here we can put request order as 1 for the using id=14 and position= 1500; or as 2 is id same and position is 2500. The cases could be found in the server.py node
def motor_callback(self, data):
_id = data.id
_position = data.position
print("_id : {0}, _position : {1}".format(_id, _position))
self.read_write(_id, _position)
def test_motor_client(self, request):
print("2")
rospy.wait_for_service('test_motor_service')
try:
proxy = rospy.ServiceProxy('test_motor_service', Motor2)
response = proxy(request)
print("response is id : {} position : {}".format(response.id, response.position))
self.read_write(response.id, response.position)
except rospy.ServiceException as e:
print("Service call failed: %s"%e)
def new_rotation(self, response):
print("3")
rospy.wait_for_service('test_mototr_rotation')
try:
proxy = rospy.ServiceProxy('test_motor_rotation', Motor2)
response = proxy(request)
self.read_write(response.id, response.position(arg[0]))
sleep(2)
self.read_write(response.id, response._position(arg[1]))
sleep(2)
self.read_write(response.id, response._position(arg[2]))
sleep(2)
except rospy.ServiceException as e:
print("Service call failed: %s"%e)
def read_write(self, _id, _position):
print("Start the node")
# Control table address
ADDR_PRO_TORQUE_ENABLE = 64 # Control table address is different in Dynamixel model
ADDR_PRO_GOAL_POSITION = 116
ADDR_PRO_PRESENT_POSITION = 132
# Protocol version
PROTOCOL_VERSION = 2.0 # See which protocol version is used in the Dynamixel
# Default setting
DXL_ID = _id # Dynamixel ID : 14
BAUDRATE = 1000000 # Dynamixel default baudrate : 1000000
DEVICENAME = '/dev/ttyUSB0' # Check which port is being used on your controller
# ex) Windows: "COM1" Linux: "/dev/ttyUSB0" Mac: "/dev/tty.usbserial-*"
TORQUE_ENABLE = 1 # Value for enabling the torque
TORQUE_DISABLE = 0 # Value for disabling the torque
DXL_MINIMUM_POSITION_VALUE = 10 # Dynamixel will rotate between this value
DXL_MAXIMUM_POSITION_VALUE = _position # The position here is already in the degree measurement; and this value (note that the Dynamixel would not move when the position value is out of movable range. Check e-manual about the range of the Dynamixel you use.)
DXL_MOVING_STATUS_THRESHOLD = 20 # Dynamixel moving status threshold
index = 0
dxl_goal_position = [DXL_MINIMUM_POSITION_VALUE, DXL_MAXIMUM_POSITION_VALUE] # Goal position
# Initialize PortHandler instance
# Set the port path
# Get methods and members of PortHandlerLinux or PortHandlerWindows
portHandler = PortHandler(DEVICENAME)
# Initialize PacketHandler instance
# Set the protocol version
# Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
packetHandler = PacketHandler(PROTOCOL_VERSION)
# Open port
if portHandler.openPort():
print("Succeeded to open the port")
else:
print("Failed to open the port")
print("Press any key to terminate...")
getch()
quit()
# Set port baudrate
if portHandler.setBaudRate(BAUDRATE):
print("Succeeded to change the baudrate")
else:
print("Failed to change the baudrate")
print("Press any key to terminate...")
getch()
quit()
# Enable Dynamixel Torque
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
print("Dynamixel has been successfully connected")
while 1:
print("Press any key to continue! (or press ESC to quit!)")
if getch() == chr(0x1b):
break
# Write goal position
dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_GOAL_POSITION, dxl_goal_position[index])
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
while 1:
# Read present position
dxl_present_position, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_PRESENT_POSITION)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
print("[ID:%03d] GoalPos:%03d PresPos:%03d" % (DXL_ID, dxl_goal_position[index], dxl_present_position))
if not abs(dxl_goal_position[index] - dxl_present_position) > DXL_MOVING_STATUS_THRESHOLD:
break
# Change goal position
if index == 0:
index = 1
else:
index = 0
# Disable Dynamixel Torque
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
print("%s" % packetHandler.getRxPacketError(dxl_error))
# Close port
portHandler.closePort()
if __name__ == '__main__':
rospy.init_node('read_write', anonymous=True)
controller = DynamixelController()
and here is the server node:
#!/usr/bin/env python
import rospy
from controller_motor.srv import Motor2, Motor2Response
def motor_info(req):
print("receive the request : {}".format(req.order))
if req.order == 1:
_id = 14
#_position = 1500
_positiondegree = 180 # change it degree value
_position = (11.4 * (_positiondegree)) # here is using there 11.4 the number which helps rotate the motor in the correct degree; We get the number encoder number/degree we want to rotate the motor.
elif req.order == 2:
_id = 14
#_position = 2047.5
_positiondegree = 180
_position = (11.4 * (_positiondegree))
print("Response to this request id : {} and postiion : {}".format(_id, _position))
return Motor2Response(_id, _position)
def motor_info_server():
rospy.init_node('test_motor_service')
s = rospy.Service('test_motor_service', Motor2, motor_info)
print("Ready to response some id and position")
# spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
motor_info_server()
Now when running the motor it rotates to the degree I would like it to rotate. And now I would like to know how could I give some degrees to make motor rotates from 0 to some other degrees and go back to the 0 degree position again.
I guess there might be applied the list and args for some degrees. But I am not well-known how I could do this :)
I would like to get some advice from professionals like you ,guys :)
I know my question could be obvious for professionals. I would like to get experience in the programming and ROS as much as I can :)
I will be so thankful for any help and advise how I could do this :)
Thank to everyone who will share his/her idea:)
I wish you have a good day :)
You have to add a new function to your code in the client file:
def rotate_bot(self,degree):
rospy.wait_for_service('rotate_motor')
try:
proxy = rospy.ServiceProxy('test_motor_rotation', Motor2)
response = proxy(degree)
except rospy.ServiceException as e:
print("Service call failed: %s"%e)
This function basically calls a Service and gives him the amount of degrees the robot has to turn. Also add this function to call the roate function:
def test_rotate(self):
rotate_bot(90)
rotate_bot(90)
rotate_bot(-180)
Now the robot turns from 0 --> 90 --> 180 --> 0
In your server file you have to add the service in the motor_info_server() method:
s = rospy.Service('test_motor_rotation', Motor2, rotate_motor)
and also add the method:
def rotate_motor(req):
print("received the request : {}".format(req.order))
degree = req.order
_id = 14
_positiondegree = degree
_position = (11.4 * (_positiondegree))
return Motor2Response(_id, _position)
If you want to pass doubles as degrees you have to change your message datatype from Motor2 to something else...
" i am trying to read data from the serial connection and doing some stuff if it matches my string but its giving me errors when i close the serial connection port"
" for some reason i do not see this error if i use the serial.readline() method "
import time
import serial
from Queue import Queue
from threading import Thread
class NonBlocking:
def __init__(self, serial_connection, radio_serial_connection):
self._s = serial_connection
self._q = Queue()
self.buf = bytearray()
def _populateQueue(serial_connection, queue):
if type(serial_connection) == str:
return
self.s = serial_connection
while True:
i = self.buf.find(b"\n")
if i >= 0:
r = self.buf[:i + 1]
self.buf = self.buf[i + 1:]
queue.put(r)
while True:
i = max(1, min(2048, self.s.in_waiting))
data = self.s.read(i)
i = data.find(b"\n")
if i >= 0:
r = self.buf + data[:i + 1]
self.buf[0:] = data[i + 1:]
a = r.split('\r\n')
for item in a:
if item:
queue.put(item)
else:
self.buf.extend(data)
self._t = Thread(target=_populateQueue, args=(self._s, self._q))
self._t.daemon = True
self._t.start()
def read_all(self, timeout=None):
data = list()
if self._q.empty():
pass
while not self._q.empty():
data.append(self._q.get(block=timeout is not None, timeout=timeout))
return data
class SerialCommands:
def __init__(self, port, baudrate):
self.serial_connection = serial.Serial(port, baudrate)
self.queue_data = NonBlocking(self.serial_connection, '')
def read_data(self):
returned_info = self.queue_data.read_all()
return returned_info
def close_q(self):
self.serial_connection.close()
class qLibrary:
def __init__(self):
self.q = None
self.port = None
def close_q_connection(self):
self.q.close_q()
def establish_connection_to_q(self, port, baudrate=115200, delay=2):
self.delay = int(delay)
self.port = port
try:
if not self.q:
self.q = SerialCommands(self.port, int(baudrate))
except IOError:
raise AssertionError('Unable to open {0}'.format(port))
def verify_event(self, data, timeout=5):
timeout = int(timeout)
data = str(data)
# print data
while timeout:
try:
to_analyze = self.q.read_data()
for item in to_analyze:
print "item: ", item
if str(item).find(str(data)) > -1:
print "Found data: '{0}' in string: '{1}'".format(data, item)
except:
pass
time.sleep(1)
timeout -= 1
if __name__ == '__main__':
q1 = qLibrary()
q1.establish_connection_to_q('COM5')
q1.verify_event("ATE")
q1.close_q_connection()
" i expect the code to close the serial connection without any exceptions or errors "
the output is
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Python27\Lib\threading.py", line 801, in __bootstrap_inner
self.run()
File "C:\Python27\Lib\threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "C:/Program Files (x86)/serialtest1.py", >line 27, in _populateQueue
data = self.s.read(i)
File "C:\Program Files (x86)\venv\lib\site->packages\serial\serialwin32.py", line 283, in read
ctypes.byref(self._overlapped_read))
TypeError: byref() argument must be a ctypes instance, not 'NoneType'
If you define your serial port with no timeout it will get the default setting timeout=None which means when you call serial.read(x) the code will block until you read x bytes.
If you never get those x bytes your code will get stuck in there waiting forever, or at least until you receive more data on the buffer to get the total number of bytes received equal to x.
If you mix that up with threading, I'm afraid you are quite likely closing the port while you are trying to read.
You can probably fix this issue just defining a sensible read timeout on your port or changing the way you read. The general advice is to set a timeout that works for your application and read at least the maximum number of bytes you expect. Reading your code, that seems to be what you wanted to do. If so, you forgot to set the timeout.
If you have a reason not to set a timeout or you want to keep your reading routine as it is, you can make your code work if you cancel reading before closing. You can do that with serial.cancel_read()
My final code is looks like the following:
#client_route.route('/client/cat-<dir_code>/subscribe/<string:user_id>', methods=['POST'])
#only_client
#is_active_client
# #cache.cached(timeout=60)
def subscribe_abonent(user_id):
search_form = Search()
client_id = Client.query.filter_by(tele=session.get('client_phone') ,name=session.get('client_logged_in'), family=session.get('client_family')).first_or_404()
master = Abonent.query.filter_by(public_id=user_id, slug_direction=g.get('current_directory')).first_or_404()
client = Client.query.filter_by(id=client_id.id).first_or_404()
if session.get('client_is_not_subscriber'):
session.pop('client_is_not_subscriber')
session['client_is_subscriber'] = client.name + client.family + str(client.id)
socketio.emit('show_calendar', namespace='/masterCalendar-{}'.format(master.slug, master.public_id.replace('-','')))
if master.email is not None:
if master.subscribers_notifications:
date_now = datetime.now()
send_email(master.email, 'You got a new subscriber','client/newsletter/new_subscriber',master=master.name + ' ' + master.family, client=client.name + " " + client.family, sent=date_now)
#celery.task
def send_email(to, subject, template, **kwargs):
with current_app.app_context():
msg = Message(current_app.config['UBOOK_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
sender=current_app.config['UBOOK_MAIL_SENDER'], recipients=[to])
msg.body = render_template(template + '.txt', **kwargs)
msg.html = render_template(template + '.html', **kwargs)
mail.send(msg)
Now everything is working fine, but celery not recognizing the task, the task runs inside the terminal just like your are sending email using Thread !!!
new_subscriber.txt:
Dear Vladimir, Here was {{master}}
You got a new subscriber:
Клиент: Sasha , Here was {{client}}
Получено: 2017-11-23 12:47:23 , Here was {{sent}}
Another thing that i forgot to mention that , if i removed the master, client and sent arguments and used delay() the code get freezed !!
I have following conditions
1. stackCreate
2. stackUpdate
3. stackCreate
What I am trying to do is, while the stackCreate/Update/Delete is triggered, I need to check on the progress. How can I do that? I know of 2 wayts
1. openstack stack event list .
2. I have below python code.
stack_id = str(hc.stacks.get(stack_name).id)
hc.stacks.delete(stack_id=stack_id)
try:
evntsdata = hc.events.list(stack_name)[0].to_dict()
event_handle = evntsdata['resource_status']
if event_handle == 'DELETE_IN_PROGRESS':
loopcontinue = True
while loopcontinue:
evntsdata = hc.events.list(stack_name)[0].to_dict()
event_handle = evntsdata['resource_status']
if event_handle == 'DELETE_COMPLETE':
loopcontinue = False
print(str(timestamp()) + " " + "Delete is Completed!")
elif event_handle == 'DELETE_FAILED':
print("Failed") # this needs a proper error msg
sys.exit(0)
else:
print(str(timestamp()) + " " + "Delete in Progress!")
time.sleep(5)
elif event_handle == 'DELETE_COMPLETE':
print(str(timestamp()) + " " + "Delete is Completed!")
sys.exit(0)
elif event_handle == 'DELETE_FAILED':
print("Failed")
sys.exit(0)
except AttributeError as e:
print(str(timestamp()) + " " + "ERROR: Stack Delete Failure")
raise
except (RuntimeError, heatclient.exc.NotFound):
print("Stack doesnt exist:", stack_name)
The first method is shell command in which I am not very good. (or lets say I dont know how to best integrate the shell command in python)
The problem with both the methods is that I am putting these many steps to identify whether the stack delete is successful. And I am repeating the same for stackupdate and create which is not best practice I am thinking. Anyone has any idea how I can minimize this logic? Any help is greatly appreciated.
You can write simple functions to create/update/delete stack and also to check the status of stack.
Please check below sample code to create a stack and poll the status of the stack.
from keystoneauth1 import loading
from keystoneauth1 import session
from heatclient import client
tenant_id = 'ab3fd9ca29e149acb25161ec8053da9c'
heat_url = 'http://10.26.12.31:8004/v1/%s' % tenant_id
auth_token = 'gAAAAABZYxfjz88XNXnfoCPkNLVeVtqtJ9o8qEtgFhI2GJ-ewSCuiypdwt3K5evgQeICVRqMa2jXgzVlENAUB19ZNyQfVCxSX4_lMBKyChM76SGuQUP8U-xJ9EKIfFaVwRGBkk4Ow9OO-iNINfMs0B5-LzJvxTFybi8yZw4EiagQpNpfu1onYfc'
heat = client.Client('1', endpoint=heat_url, token=auth_token)
def create_stack(stack_file_path, stack_name, parameters=None):
template = open(stack_file_path)
if parameters:
stack = heat.stacks.create(stack_name=stack_name, template=template.read(), parameters=parameters)
else:
stack = heat.stacks.create(stack_name=stack_name, template=template.read())
template.close()
return stack
def get_stack_status(stack_id):
stack = heat.stacks.get(stack_id)
return stack.stack_status
def poll_stack_status(stack_id, poll_time=5):
stack_status = get_stack_status(stack_id)
while stack_status != 'CREATE_COMPLETE':
if stack_status == 'CREATE_FAILED':
return 1
time.sleep(poll_time)
stack_status = get_stack_status(stack_id)
return 0
I worked it with below for now. It's not the best I think but satisfies what I need to do.
def stackStatus(status):
evntsdata = hc.events.list(stack_name)[0].to_dict()
event_handle = evntsdata['resource_status'].split("_")
event_handle = '_'.join(event_handle[1:])
if event_handle == 'IN_PROGRESS':
loopcontinue = True
while loopcontinue:
evntsdata = hc.events.list(stack_name)[0].to_dict()
event_handle = evntsdata['resource_status'].split("_")
event_handle = '_'.join(event_handle[1:])
if event_handle == 'COMPLETE':
loopcontinue = False
print(str(timestamp()) + status + " IS COMPLETED!")
elif event_handle == 'FAILED':
print("Failed")
exit(1)
else:
print(str(timestamp()) + status + " IN PROGRESS!")
time.sleep(5)
Call this function
stackStatus("DELETE")
stackStatus("CREATE")
stackStatus("UPDATE")