How to pass serial_asyncio between async tasks - python

I need to pass reader and writer from serial_asyncio between 2 asynchronous tasks, first task is reading user keyboard input, when user press x, function send information to Arduino, second task reading response from Arduino and for specyfic response do stuff
Code:
import warnings
import serial
import serial.tools.list_ports
import requests
import json
import asyncio
import keyboard
import time
from serial_asyncio import open_serial_connection
with open("config.json") as config:
cfg = json.load(config)
config.close()
headers = {'Accept': 'application/json'}
url = f"""https://{cfg["web"]}/login?username={cfg["user"]}&password={cfg["password"]}"""
get_token = requests.post(url, headers=headers)
token = get_token.json()
my_token = token["token"]
arduino_ports = [
p.device
for p in serial.tools.list_ports.comports()
if p.manufacturer and 'Arduino' in p.manufacturer
]
if not arduino_ports:
raise IOError("No Arduino found")
if len(arduino_ports) > 1:
warnings.warn("Multiple arduinos, select first")
async def arduino_listen(cfg, headers, reader):
print('arduino_listen task created')
while True:
await asyncio.sleep(0.1)
info = await reader.readline()
print('arduino respond:', info)
if "good" in str(info):
print('good from arduino')
if "bad" in str(info):
print('bad from arduino')
async def arduino_writer(cfg, headers, writer):
print('arduino_writer task created')
keypress = False
key = 'x'
while True:
if keypress and not keyboard.is_pressed(key):
print('x pressed on keyboard, send 5')
writer.write(b'5')
await asyncio.sleep(0.3)
keypress = False
elif keyboard.is_pressed(key) and not keypress:
keypress = True
async def serial():
print(f'serial task created, arduino port {arduino_ports[0]} selected')
reader, writer = await open_serial_connection(url=arduino_ports[0], baudrate=115200)
#reader, writer = await open_serial_connection(url=arduino_ports[0], baudrate=115200)
loop = asyncio.get_event_loop()
loop.create_task(serial())
loop.create_task(arduino_listen(cfg, headers, reader))
loop.create_task(arduino_writer(cfg, headers, writer))
loop.run_forever()
My question is, how to pass connection from serial function task to arduino_listen and arduino_writer tasks, I have try to add reader, writer = await open_serial_connection(url=arduino_ports[0], baudrate=115200) before loop.create_task but error unexpected ident appear

Avoid giving functions name that conflict with your module names, it's about serial in your case. Let's call it say start_serial.
As start_serial is the initial function that starts a serial connection arduino_listen and arduino_writer should be run in parallel right after it.
Change the final part of your code to the following:
async def start_serial():
print(f'serial task created, arduino port {arduino_ports[0]} selected')
reader, writer = await open_serial_connection(url=arduino_ports[0], baudrate=115200)
return reader, writer
async def main():
reader, writer = await start_serial()
await asyncio.gather(
arduino_listen(cfg, headers, reader),
arduino_writer(cfg, headers, writer))
asyncio.run(main())

Related

Discord.py async-await won't close connection with Airflow DAG/Task

I'm trying to post a dataframe to a Discord channel. However, I am having issue getting Discord.py to close the connection and move on the next task. I've tried using the event loop as suggested in this thread (How to run async function in Airflow?) as well as asyncio.run() function. Not really familiar with the async and hoping to get some pointers here. Below is my code in Python that I've tried importing in DAG and Task without success. Thanks in advance!
Airflow: 2.5.1
Python: 3.7
import discord
from tabulate import tabulate
import asyncio
import pandas as pd
async def post_to_discord(df, channel_id, bot_token, as_message=True, num_rows=5):
intents = discord.Intents.default()
intents.members = True
client = discord.Client(intents=intents)
try:
#client.event
async def on_ready():
channel = client.get_channel(channel_id)
if as_message:
# Post the dataframe as a message, num_rows rows at a time
for i in range(0, len(df), num_rows):
message = tabulate(df.iloc[i:i+num_rows,:], headers='keys', tablefmt='pipe', showindex=False)
await channel.send(message)
else:
# Send the dataframe as a CSV file
df.to_csv("dataframe.csv", index=False)
with open("dataframe.csv", "rb") as f:
await channel.send(file=discord.File(f))
# client.run(bot_token)
await client.start(bot_token)
await client.wait_until_ready()
finally:
await client.close()
async def main(df, channel_id, bot_token, as_message=True, num_rows=5):
# loop = asyncio.get_event_loop()
# result = loop.run_until_complete(post_to_discord(df, channel_id, bot_token, as_message, num_rows))
result = asyncio.run(post_to_discord(df, channel_id, bot_token, as_message, num_rows))
await result
return result
if __name__ =='__main__':
main()
It seems like your script works but the server is blocking the open socket (and kudos - the discord server is good at that). So we will work by creating a ping function (adopted from another answer).
def ping(ip, port):
try:
s = socket.socket() # TCP - standard values are `socket.AF_INET, socket.SOCK_STREAM` so you don't have to write them
s.settimeout(2)
print('[DEBUG] connect')
s.connect((ip, int(port)))
#result = s.connect_ex((ip, int(port)))
#print('result:', result)
return True
except socket.timeout as ex:
print('[DEBUG] timeout')
return True
except Exception as ex:
print('[Exception]', ex)
return False
finally:
print('[DEBUG] close')
s.close()
Feel free to test your ID
id = ...channel number...
print(id, type(id))
and you should see
<built-in function id> <class 'builtin_function_or_method'>
Then let us move on to improving your code:
import discord
import asyncio
import time # you are not using this module
import socket
import os
from tabulate import tabulate
import pandas as pd # as pd is not required
def ping(ip, port):
try:
s = socket.socket() # TCP - standard values are `socket.AF_INET, socket.SOCK_STREAM` so you don't have to write them
s.settimeout(2)
print('[DEBUG] connect')
s.connect((ip, int(port)))
#result = s.connect_ex((ip, int(port)))
#print('result:', result)
return True
except socket.timeout as ex:
print('[DEBUG] timeout')
return True
except Exception as ex:
print('[Exception]', ex)
return False
finally:
print('[DEBUG] close')
s.close()
TOKEN = os.getenv('DISCORD_TOKEN')
client = discord.Client()
async def post_to_discord(df, channel_id, bot_token, as_message=True, num_rows=5):
intents = discord.Intents.default()
intents.members = True
client = discord.Client(intents=intents)
try:
#client.event
async def on_ready():
channel = client.get_channel(channel_id)
if as_message:
# Post the dataframe as a message, num_rows rows at a time
for i in range(0, len(df), num_rows):
message = tabulate(df.iloc[i:i+num_rows,:], headers='keys', tablefmt='pipe', showindex=False)
await channel.send(message)
else:
# Send the dataframe as a CSV file
df.to_csv("dataframe.csv", index=False)
with open("dataframe.csv", "rb") as f:
await channel.send(file=discord.File(f))
# client.run(bot_token)
await client.start(bot_token)
await client.wait_until_ready()
while True:
online = ping("26.51.174.109", "25565") #modify it as you see fit
#online = ping("192.168.1.101", "8081") #same as above
if online:
print("server online")
#await channel.edit(name="Server Status - Online")
else:
print("server offline")
#await channel.edit(name="Server Status - Offline")
await asyncio.sleep(5)
# optional - client.run(TOKEN)
finally:
await client.close()
async def main(df, channel_id, bot_token, as_message=True, num_rows=5):
# loop = asyncio.get_event_loop()
# result = loop.run_until_complete(post_to_discord(df, channel_id, bot_token, as_message, num_rows))
result = asyncio.run(post_to_discord(df, channel_id, bot_token, as_message, num_rows))
await result
return result
if __name__ =='__main__':
main()

StreamReader.readline() does not return upon reading a newline

So I have been trying to experiment with Streams in Python and wrote the following code.
ServiceSubscription.py
class ServiceSubscription():
def __init__(self) -> None:
self.subscriber_connections = []
self.service_connections = []
self.server_listener = None
# Dictionary of service readers where key is the name of the service and the value is the reader for the service
self.service_readers = {}
"""
Create the listening server on port 7777
"""
async def initiate_server(self):
server = await asyncio.start_server(self.handle_incoming, '127.0.0.1', 7777)
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
print(f'Serving on {addrs}')
async with server:
await server.serve_forever()
"""
Handle the incoming connection based on whether the connection is from a service or suscriber
The first message sent should include either 'service:SERVICE_NAME' or 'suscriber: [SERVICE1, SERVICE2, ...]'
"""
async def handle_incoming(self, reader: StreamReader, writer: StreamWriter):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print(f"Received {message!r} from {addr!r}")
if ("Service:" in f"{message!r}"):
message = message[0:7]
self.service_connections.append(Connections(reader, writer, message))
service_reader = ServiceReader(reader=reader, writer=writer)
self.service_readers[message] = (service_reader)
await service_reader.broadcast()
elif ("Suscriber:" in f"{message!r}"):
message = message[0:9]
self.subscriber_connections.append(Connections(reader, writer, message))
self.service_readers[message].add_suscribers(writer)
else:
pass
class ServiceReader():
def __init__(self, reader: StreamReader, writer: StreamWriter):
self.reader = reader
self.writer = writer
self.suscribers: Writer = []
self.loop = asyncio.get_event_loop()
def stop(self):
self._stop.set()
"""
Add new subscriber's StreamWriter here
"""
def add_suscribers(self, writer: StreamWriter):
# Not sure if this will work
self.suscribers.append(writer)
"""
Read data and broadcast it to subscribed clients
"""
async def broadcast(self):
while not self.reader.at_eof():
data = await self.reader.readline()
if b'\n' in data:
print(True)
data = data.decode()
print(data)
WriterTest.py
import asyncio
from os import linesep
async def tcp_echo_client(message):
reader, writer = await asyncio.open_connection(
'127.0.0.1', 7777)
print(f'Send: {message!r}\n')
writer.write(message.encode())
await writer.drain()
while not writer.is_closing():
data = input("Type a message\n")
data = (data + "\n").encode()
writer.write(data)
await writer.drain()
writer.close()
asyncio.run(tcp_echo_client('Service: TEST'))
I ran both python ServiceSubscription.py and python WriterTest.py at the same time to simulate a client and server.
Upon running ServiceSubscription.py, it will print "Serving on ('127.0.0.1', 7777)". When WriterTest.py is executed, ServiceSubscription.py will print "Received 'Service: TEST' from ('127.0.0.1', 39923)". However, typing anything beyond that will not be printed out until WriterTest.py's connection is closed. When the connection is closed, ServiceSubcription.py prints out the remaining bytes in the buffer and also confirms that there are newlines in the data read but it is not picked up by readline as it doesn't return after encountering a newline.
The problem is here, in your WriterTest:
data = input("Type a message\n")
The input function is blocking, so in an asyncio program it blocks the event loop. All tasks are stopped until you enter something. With asyncio streams, the actual transmission of the bytes occurs in another task. Your call to the input function blocks that task, which prevents the transmission. Your server doesn't respond because nothing is actually sent.
Since this is just a test program, you have a couple of quick solutions. You could put this line:
await asyncio.sleep(1.0)
after the line await writer.drain(). This will keep the other tasks running for one second, plenty of time for the data to get transmitted.
You could, of course, replace the call to input with some hard-coded string.
Better solutions can be found at the following link:
Listen to keypress with asyncio
As a general rule, input and asyncio do not play well together.
Data is encoded alongside a break line and a couple of variables are unpacked as reader and writer objects, then meanwhile is_closing() is waiting for a closing process, that should be close(), you could try to set a conditional when message have no characters.
import asyncio
import sys
from os import linesep
async def tcp_echo_client(message):
reader, writer = await asyncio.open_connection(
'127.0.0.1', 7777)
print(f'Send: {message!r}\n')
writer.write(message.encode())
await writer.drain()
while not writer.is_closing():
await asyncio.get_event_loop().run_in_executor(None, lambda s="Type a message\n": sys.stdout.write(s+' '))
data = await asyncio.get_event_loop().run_in_executor(None, sys.stdin.readline)
if len(data)==0: # empty data
break
data = (data + "\n").encode()
writer.write(data)
await writer.drain()
print('Close the connection')
writer.close()
await writer.wait_closed()
here I change while conditional to check instead if data is empty and use a different corountine from asyncio
async def broadcast(self):
while True:
data = asyncio.wait_for(self.reader.readline(), timeout=10.0)
if data is None or len(data.decode()) == 0:
print("Expected message, received None")
break
data = data.decode().rstrip().upper()
print(data)

NATS WEBSOCKET Python WebSocket Connection

I want to do the following thing:
I want to make a websocket, which prints me all events about esports and I want to use https://sofascore.com
I've inspected the network requests as usual and it seems that I need to send a Auth WebSocket Content first, then one for subscribing the right sport and then I will receive my events I need.
I've wrote the following code:
import websockets
import asyncio
from websockets.extensions import permessage_deflate
async def esports():
async with websockets.connect('wss://ws.sofascore.com:9222/', compression='deflate') as websocket:
msg = await websocket.recv()
print(f"From Server: {msg}")
t = await websocket.send(
'CONNECT {"no_responders":true,"protocol":1,"verbose":false,"pedantic":false,"user":"none","pass":"none","lang":"nats.ws","version":"1.8.1","headers":true}')
await websocket.send("PING")
pong = await websocket.recv()
print(f"From Server: {pong}")
await websocket.send(
'SUB sport.esports 6')
while (True):
msg = await websocket.recv()
print(f"From Server: {msg}")
asyncio.get_event_loop().run_until_complete(esports())
I know that the websocket is compressed as permessage_deflate, when I saw into the request headers of the websocket.
But I still get an error:
Traceback (most recent call last):
File "C:\Users\Coding\Desktop\websockett.py", line 23, in <module>
asyncio.get_event_loop().run_until_complete(esports())
File "C:\Users\Coding\AppData\Local\Programs\Python\Python39-32\lib\asyncio\base_events.py", line 642, in run_until_complete
return future.result()
File "C:\Users\Coding\Desktop\websockett.py", line 15, in esports
await websocket.send(
File "C:\Users\Coding\AppData\Roaming\Python\Python39\site-packages\websockets\legacy\protocol.py", line 620, in send
await self.ensure_open()
File "C:\Users\Coding\AppData\Roaming\Python\Python39\site-packages\websockets\legacy\protocol.py", line 921, in ensure_open
raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedError: received 1008 (policy violation) Authentication Timeout; then sent 1008 (policy violation) Authentication Timeout
Process finished with exit code 1
EDIT:
I have now found out that the whole thing works with the Nats network. Is there any way to use Nats with a Libary that also supports the websockets?
Haven't found one on github or pypi unfortunately....
Ideally you would be able to use the nats-py library:
import asyncio
import nats
async def handler(msg):
print(f"From server: {msg}")
async def main():
nc = await nats.connect("wss://ws.sofascore.com:9222")
await nc.subscribe("sport.esports", cb=handler)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
try:
loop.run_forever()
finally:
loop.close()
However, this library does not currently support connecting with WebSockets, so
the above doesn't work (yet - it looks like it's being worked on right
now).
For your code, the only reason it fails is that the messages you're sending
don't end with \r\n, which the NATS protocol requires. The code works as
expected with this change:
import asyncio
import websockets
async def esports():
async with websockets.connect('wss://ws.sofascore.com:9222') as websocket:
msg = await websocket.recv()
print(f"From Server: {msg}")
await websocket.send(
'CONNECT {"no_responders":true,"protocol":1,"verbose":false,"pedantic":false,"user":"none","pass":"none","lang":"nats.ws","version":"1.8.1","headers":true}\r\n'
)
await websocket.send("SUB sport.esports 1\r\n")
async for msg in websocket:
print(f"From Server: {msg}")
asyncio.run(esports())
Of course this will eventually get disconnected because it doesn't respond to
PING messages. Here's a little more fleshed out script which implements enough
of the NATS protocol to log the sport.esports messages:
import asyncio
import json
import textwrap
from dataclasses import dataclass
import websockets
class SofaError(Exception):
pass
def message_string(message, data=None, pretty=False):
s = message
if data is not None:
if pretty:
s += json.dumps(data, indent=2)
else:
s += json.dumps(data, separators=(",", ":"))
return s
def log(pre, message, data=None):
print(textwrap.indent(message_string(message, data, True), pre))
def recv_log(message, data=None):
log("< ", message, data)
async def send(websocket, message, data=None):
log("> ", message, data)
data = (message_string(message, data, False) + "\r\n").encode()
await websocket.send(data)
async def connect_and_subscribe(websocket):
connect_options = {
"no_responders": True,
"protocol": 1,
"verbose": False,
"pedantic": False,
"user": "none",
"pass": "none",
"lang": "nats.ws",
"version": "1.8.1",
"headers": True,
}
await send(websocket, "CONNECT ", connect_options)
await send(websocket, "SUB sport.esports 1")
#dataclass
class NatsMsg:
subject: str
sid: str
reply_to: str
size: int
payload: bytes
def parse_msg(info_line, pending_data):
if not info_line:
raise SofaError("No payload information received")
info = [b.decode(errors="replace") for b in info_line.split(b" ")]
if len(info) == 3:
subject, sid, size = info
reply_to = None
elif len(info) == 4:
subject, sid, reply_to, size = info
else:
raise SofaError("Unrecognized info format")
try:
size = int(size)
except ValueError:
raise SofaError("Bad payload size")
if len(pending_data) < size:
raise SofaError("Incomplete payload")
payload = pending_data[:size]
pending_data = pending_data[size:]
return NatsMsg(subject, sid, reply_to, size, payload), pending_data
async def handler(websocket, ws_message, connected):
while len(ws_message):
nats_message, _, ws_message = ws_message.partition(b"\r\n")
if not nats_message:
continue
op, _, rest = nats_message.partition(b" ")
if op == b"-ERR":
recv_log(nats_message.decode(errors="replace"))
err = rest.strip(b"'").decode(errors="replace") if rest else "(No message received)"
raise SofaError(f"Server error: {err}")
elif op == b"INFO":
info_options = json.loads(rest) if rest else None
recv_log("INFO ", info_options)
if not connected:
await connect_and_subscribe(websocket)
connected = True
elif op == b"PING":
recv_log("PING")
await send(websocket, "PONG")
elif op == b"MSG":
try:
msg, ws_message = parse_msg(rest, ws_message)
except SofaError as e:
recv_log(f"MSG (Error: {e}) {rest}")
continue
msg_info = (
f"MSG subject={msg.subject} sid={msg.sid} "
f"reply-to={msg.reply_to} nbytes={msg.size}:\n"
)
try:
decoded = msg.payload.decode()
data = json.loads(decoded)
except UnicodeError:
recv_log(f"{msg_info}{msg.payload}")
except json.JSONDecodeError:
recv_log(f"{msg_info}{decoded}")
else:
recv_log(msg_info, data)
else:
recv_log(f"(Unhandled op) {nats_message.decode(errors='replace')}")
return connected
async def main():
async with websockets.connect("wss://ws.sofascore.com:9222") as websocket:
connected = False
async for message in websocket:
connected = await handler(websocket, message, connected)
if __name__ == "__main__":
asyncio.run(main())

Websockets Server Push in Python

How do I write a websockets server in Python which just pushes out data on a timed interval to all connected clients without waiting for any incoming messages ?
I'm answering my own question ...
This is a working example of a Python websockets server which sends out a message to all clients every 5 seconds. I wrote this and managed to get it working as I could not find a single example of this on the web (March 2021)
Hope this helps others, and if anyone has suggestions for improvements or better solutions using packages to maybe add ssl support or subscription type services additions, please write in the comments or answers section.
import asyncio
import logging
import websockets
from websockets import WebSocketServerProtocol
import time
import threading
logging.basicConfig(level=logging.INFO)
class Server:
clients = set()
logging.info(f'starting up ...')
def __init__(self):
logging.info(f'init happened ...')
async def register(self, ws: WebSocketServerProtocol) -> None:
self.clients.add(ws)
logging.info(f'{ws.remote_address} connects')
async def unregister(self, ws: WebSocketServerProtocol) -> None:
self.clients.remove(ws)
logging.info(f'{ws.remote_address} disconnects')
async def send_to_clients(self, message: str) -> None:
if self.clients:
logging.info("trying to send")
await asyncio.wait([client.send(message) for client in self.clients])
async def ws_handler(self, ws: WebSocketServerProtocol, url: str) -> None:
await self.register(ws)
try:
await self.distribute(ws)
finally:
await self.unregister(ws)
async def distribute(self, ws: WebSocketServerProtocol) -> None:
async for message in ws:
await self.send_to_clients(message)
async def timerThread(server,counter):
counter = 0
while True:
await checkAndSend(server,counter)
print("doing " + str(counter))
time.sleep(5)
counter = counter + 1
async def checkAndSend(server,counter):
# check something
# send message
logging.info("in check and send")
await server.send_to_clients("Hi there: " + str(counter))
# helper routine to allow thread to call async function
def between_callback(server,counter):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(timerThread(server,counter))
loop.close()
# start server
server = Server()
start_server = websockets.serve(server.ws_handler,'localhost',4000)
counter = 0
# start timer thread
threading.Thread(target=between_callback,args=(server,counter,)).start()
# start main event loop
loop = asyncio.get_event_loop()
loop.run_until_complete(start_server)
loop.run_forever()
To see this working, you can use this simple html file as the client and then open the inspector to see the incoming messages on the Console log.
<h1> Websocket Test </h1>
<script>
const ws = new WebSocket('ws://localhost:4000')
ws.onopen = () => {
console.log('ws opened on browser')
ws.send('hello world')
}
ws.onmessage = (message) => {
console.log(`message received`, message.data)
}
</script>
from datetime import time
import schedule
import time
import socket
import threading
alarm_time = input()
my_string = str(alarm_time)
my_new_time = my_string.format("%H:%M %Z")
EADER = 64
PORT = xxxx
SERVER = 'xxxxxxxx'
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
if alarm_time is not None and alarm_time != 0:
print(f"Scheduled for: {my_new_time}")
else:
sys.exit()
def job():
client.connect(ADDR)
name_time = self.name_send + ' ' + my_date
message = name_time.encode(FORMAT)
msg_length = len(message)
send_length = str(msg_length).encode(FORMAT)
send_length += b' ' * (HEADER - len(send_length))
client.send(send_length)
client.send(message)
schedule.every().day.at(my_new_time).do(job)
while True:
schedule.run_pending()
time.sleep(1)
Not sure if this is any help tbh. But its a small tweak of a script I use with socket, subprocess etc to schedule them

Reading from pipe with pexpect on Linux

I post a new question related the old for a problem with the get from queue. This is the code (thanks to Martijn Pieters)
import asyncio
import sys
import json
import os
import websockets
async def socket_consumer(socket, outgoing):
# take messages from the web socket and push them into the queue
async for message in socket:
await outgoing.put(message)
file = open(r"/home/host/Desktop/FromSocket.txt", "a")
file.write("From socket: " + ascii(message) + "\n")
file.close()
async def socket_producer(socket, incoming):
# take messages from the queue and send them to the socket
while True:
message = await incoming.get()
file = open(r"/home/host/Desktop/ToSocket.txt", "a")
file.write("To socket: " + ascii(message) + "\n")
file.close()
await socket.send(message)
async def connect_socket(incoming, outgoing, loop=None):
header = {"Authorization": r"Basic XXX="}
uri = 'XXXXXX'
async with websockets.connect(uri, extra_headers=header) as web_socket:
# create tasks for the consumer and producer. The asyncio loop will
# manage these independently
consumer_task = asyncio.ensure_future(
socket_consumer(web_socket, outgoing), loop=loop)
producer_task = asyncio.ensure_future(
socket_producer(web_socket, incoming), loop=loop)
# start both tasks, but have the loop return to us when one of them
# has ended. We can then cancel the remainder
done, pending = await asyncio.wait(
[consumer_task, producer_task], return_when=asyncio.FIRST_COMPLETED)
for task in pending:
task.cancel()
# pipe support
async def stdio(loop=None):
if loop is None:
loop = asyncio.get_event_loop()
reader = asyncio.StreamReader()
await loop.connect_read_pipe(
lambda: asyncio.StreamReaderProtocol(reader), sys.stdin)
writer_transport, writer_protocol = await loop.connect_write_pipe(
asyncio.streams.FlowControlMixin, os.fdopen(sys.stdout.fileno(), 'wb'))
writer = asyncio.streams.StreamWriter(
writer_transport, writer_protocol, None, loop)
return reader, writer
async def pipe_consumer(pipe_reader, outgoing):
# take messages from the pipe and push them into the queue
while True:
message = await pipe_reader.readline()
if not message:
break
file = open(r"/home/host/Desktop/FromPipe.txt", "a")
file.write("From pipe: " + ascii(message.decode('utf8')) + "\n")
file.close()
await outgoing.put(message.decode('utf8'))
async def pipe_producer(pipe_writer, incoming):
# take messages from the queue and send them to the pipe
while True:
json_message = await incoming.get()
file = open(r"/home/host/Desktop/ToPipe.txt", "a")
file.write("Send to pipe message: " + ascii(json_message) + "\n")
file.close()
try:
message = json.loads(json_message)
message_type = int(message.get('header', {}).get('messageID', -1))
except (ValueError, TypeError, AttributeError):
# failed to decode the message, or the message was not
# a dictionary, or the messageID was convertable to an integer
message_type = None
file = open(r"/home/host/Desktop/Error.txt", "a")
file.write(" Error \n")
file.close()
# 1 is DENM message, 2 is CAM message
file.write("Send to pipe type: " + type)
if message_type in {1, 2}:
file.write("Send to pipe: " + json_message)
pipe_writer.write(json_message.encode('utf8') + b'\n')
await pipe_writer.drain()
async def connect_pipe(incoming, outgoing, loop=None):
reader, writer = await stdio()
# create tasks for the consumer and producer. The asyncio loop will
# manage these independently
consumer_task = asyncio.ensure_future(
pipe_consumer(reader, outgoing), loop=loop)
producer_task = asyncio.ensure_future(
pipe_producer(writer, incoming), loop=loop)
# start both tasks, but have the loop return to us when one of them
# has ended. We can then cancel the remainder
done, pending = await asyncio.wait(
[consumer_task, producer_task], return_when=asyncio.FIRST_COMPLETED)
for task in pending:
task.cancel()
# force a result check; if there was an exception it'll be re-raised
for task in done:
task.result()
def main():
loop = asyncio.get_event_loop()
pipe_to_socket = asyncio.Queue(loop=loop)
socket_to_pipe = asyncio.Queue(loop=loop)
socket_coro = connect_socket(pipe_to_socket, socket_to_pipe, loop=loop)
pipe_coro = connect_pipe(socket_to_pipe, pipe_to_socket, loop=loop)
loop.run_until_complete(asyncio.gather(socket_coro, pipe_coro))
main()
To send to the Pipe I use this code:
import pexpect
test = r"/home/host/PycharmProjects/Tim/Tim.py"
process = pexpect.spawn("python3 " + test)
message = '{"header":{"protocolVersion":1,"messageID":2,"stationID":400},"cam":{"generationDeltaTime":1,"camParameters":{"basicContainer":{"stationType":5}}';
process.write(message + "\n")
process.wait()
but how can I create a script to read instead of write?
I tried with
test = r"/home/host/PycharmProjects/Tim/Tim.py"
p = pexpect.spawn("python3 " + test, timeout=None)
while True:
m = p.read()
file = open(r"/home/host/Desktop/OpeListening.txt", "a")
file.write(str(m))
file.close()
p.wait()
But the read goes immediately to the next step without any message. What is my error?
At the moment I use with success Popen
process = subprocess.Popen(['python3', test], shell=False, stdout=subprocess.PIPE,
stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
result = process.stdout.readline()
result = result.decode("utf-8")
print(result)
proc.wait()

Categories

Resources