Python async input - python-asyncio

I'm trying to perform some actions during getting input from a user. I found this question but both answers not working for me.
My code:
In [1]: import asyncio
In [2]: import aioconsole
In [3]:
In [3]:
In [3]: async def test():
...: await asyncio.sleep(5)
...: await aioconsole.ainput('Is this your line? ')
...: await asyncio.sleep(5)
In [4]: asyncio.run(test()) # sleeping, input, sleeping (synchronously)
I'm expecting that input will be accessible during sleeping (or simple counting for example), but it's not happening.
What I do wrong?

What I do wrong?
You used await, which (as the name implies) means "wait". If you want things to happen at the same time, you need to tell them to run in the background, e.g. using asyncio.create_task() or concurrently, e.g. using asyncio.gather(). For example:
async def say_hi(message):
await asyncio.sleep(1)
print(message)
async def test():
_, response, _ = await asyncio.gather(
say_hi("hello"),
aioconsole.ainput('Is this your line? '),
say_hi("world"),
)
print("response was", response)
asyncio.run(test())

Related

Nextcord typing through discord bot

I would like to be able to asynchronously send inputs to my python terminal and have my bot output them, whilst also keeping my other event running.
import nextcord
import botToken #contains the string of my bot token
from nextcord.ext import commands
client = commands.Bot(command_prefix="!")
#client.event
async def on_ready():
general = client.get_channel(925388635304521859)
while True:
inp = input("->")
if len(inp) < 4001:
await general.send(inp)
else:
await general.send(inp[0: 1500])
#client.event
async def on_message(message): #its supposed to react to each message with a buffalo emoji
print(message.content)
channel = message.channel
if "<#!308022163330564099>" in message.content:
await message.delete()
await channel.send("🐃")
await message.add_reaction("🐃")
client.run(botToken.TOKEN)e
Currently the on_ready() event only loads when it starts which is good, but i would like it to be asyncronic if thats a possibility. I don't know much about nextcord so I have no ideas. I would love any ideas for this.
The tasks extension in Nextcord may help for what you are trying to do
https://nextcord.readthedocs.io/en/latest/ext/tasks/index.html
It allows you to execute code in the background using a loop.
from nextcord.ext import tasks
#tasks.loop(seconds=1.0)
async def my_task_loop():
print("Hello!")
#my_task_loop.before_loop
async def before_my_task_loop():
print('waiting for ready')
await self.bot.wait_until_ready()
my_task_loop.start()

Simple syntax to asynchronously get access to MODBUS register

I am trying to run three simple tasks in parallel using asyncio and sharing global variables.
Two of them are working perfectly. One read websockets ("async with websockets.connect("ws://192.168.1.137:9000") as websocket:" Another one access IO via a dedicated library.
I did not find any solution and the good syntax for getting AsyncModbusTCPClient running within the third task (sync MODBUS is easy to implement but would not fit within async task)
The following would just block everything:
async def get_var_modbus(loop):
client = await AsyncModbusTCPClient( schedulers.ASYNC_IO,host="192.168.1.200", loop=loop, port=502, timeout=20, unit=3)
while True:
print("INIT")
print("Reading coils")
rr = await client.read_input_registers(0, 1, unit=0x03)
print(rr.registers)
await asyncio.sleep(1)
Full code below
from pymodbus.client.asynchronous import schedulers
from pymodbus.client.asynchronous.tcp import AsyncModbusTCPClient
import json
import time
from pypx800v5 import *
import aiohttp
import asyncio
import requests_async as requests
import numpy as np
import logging
from datetime import datetime
import websockets
import contextvars
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
# SDM230 via MODBUS
SDM230A=["Voltage","Current","Active Power","Apparent Power","Reactive Power","Power Factor","Phase Angle","Frequency","Import Active Energy","Export Active Energy","Import Reactive Energy","Export Reactive Energy"]
SDM230B=["Total system power demand","Maximum total system power demand","Current system positive power demand","Maximum system positive power demand","Current system reverse power demand","Maximum system reverse power demand"]
SDM230C=["Current demand","Maximum current Demand"]
SDM230D=["Total Active Energy","Total Reactive Energy"]
SDM230Labels=SDM230A+SDM230B+SDM230C+SDM230D
SDM230Var=["Voltage","Current","ActivePower","ApparentPower","ReactivePower","PowerFactor","PhaseAngle","Frequency","ImportActiveEnergy","ExportActiveEnergy","ImportReactiveEnergy","ExportReactiveEnergy","TotalSysPowerDemand","MaxTotalSysPowerDemand","CurrentSysPositivePowerDemand","MaxSysPositivePowerDemand","CurrentSysReversePowerDemand","MaxSysReversePowerDemand","CurrentDemand","MaximumCurrentDemand","TotalActiveEnergy","TotalReactiveEnergy"]
VoltageAdd=262199
CurrentAdd=262200
ActivePowerAdd=262201
ImportActiveEnergyAdd=262202
# inversor via Websockets
TempChaudiereAdd=262198
PuissMaxChauffeauAdd=262193
WREDAdd=262194
PacBat6TLAdd=262195
totPVAdd=262196
SOC6TLAdd=262197
# shared variables
WRED= 0
PacBat6TL=0
PacPV6TL=0
Pac6TLM=0
SOC6TL=0
PAC6TL=0
totPV=0
# --------------------------------------------------------------------------- #
# configure the client logging
# --------------------------------------------------------------------------- #
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
async def get_var_modbus(loop):
client = await AsyncModbusTCPClient( schedulers.ASYNC_IO,host="192.168.1.200", port=502, loop=loop, timeout=20, unit=3)
while True:
print("INIT")
print("Reading coils")
rr = await client.read_input_registers(0, 1, unit=0x03)
print(rr.registers)
await asyncio.sleep(1)
async def get_var_socket():
global WRED
global PacBat6TL
global PacPV6TL
global Pac6TLM
global SOC6TL
global PAC6TL
global totPV
print("")
i=0
dict={}
async with websockets.connect("ws://192.168.1.137:9000") as websocket:
while True:
i=i+1
data=(await websocket.recv())
try:
message=json.loads(data)
except:
break
if "product" in message:
if message["product"]=="ems":
print(message)
if "WRED" in message:
WRED=message["WRED"]
if "PacBat6TL" in message:
PacBat6TL=message["PacBat6TL"]
if "PacPV6TL" in message:
PacPV6TL=message["PacPV6TL"]
totPV=PacPV6TL
if "Pac6TLM" in message:
Pac6TLM=message["Pac6TLM"]
totPV=totPV+Pac6TLM
if "SOC6TL" in message:
SOC6TL=message["SOC6TL"]
if "PAC6TL" in message:
PAC6TL=message["PAC6TL"]
async def get_ipx_update():
print("")
i=0
dict={}
async with IPX800(host='192.168.1.139', api_key='API') as ipx:
await ipx.init_config()
while True:
try:
await ipx.update_ana(WREDAdd,WRED)
except:
print("ERROR")
try:
await ipx.update_ana(PacBat6TLAdd,PacBat6TL)
except:
print("ERROR")
try:
await ipx.update_ana(totPVAdd,totPV)
except:
print("ERROR")
try:
await ipx.update_ana(SOC6TLAdd,SOC6TL)
except:
print("ERROR")
await asyncio.sleep(1)
def main():
loop = asyncio.get_event_loop()
loop.create_task(get_var_socket())
loop.create_task(get_ipx_update())
loop.create_task(get_var_modbus(loop))
loop.run_forever()
if __name__ == '__main__':
try:
main()
except Exception as f:
print('main error: ', f)
sleep(3)
Using the async_modbus library (built on the top of umodbus https://pypi.org/project/async-modbus/) it works very well.
I have used this library with success.
Please find below the syntax,
async def get_var_modbus(loop):
reader, writer = await asyncio.open_connection('192.168.1.200', 502)
client = AsyncTCPClient((reader, writer))loop=loop, port=502, timeout=20, unit=3)
while True:
print("Reading holding registers ADAM3066")
reply = await client.read_holding_registers(slave_id=3, starting_address=0, quantity=8)
print("reply:",reply)
await asyncio.sleep(1)
OUTPUT:
Reading holding registers ADAM3066
reply: [65535 65535 65535 65535 289 65535 65535 65535]
The ADAM 3066 is a RS-485 MODBUS RTU 1-WIRE interface connected to a MODBUS TCP gateway at 192.168.1.200, I have one sensor connected on the input 5 of ADAM 3066 which return a temperature of 28.9 degrees C

Discord bot repeating the command but not an event in discord.py

I want to ask something.I got stuck on something.I wanted to add some new features to my bot such as swear words so that making cleaner server.I finished my code and tried to give command which is !dc greetings(!dc is my command_prefix btw).My bot sent 'Hi everyone' message for 7 times.That 7 times is same number as the number of swear words in "Badwords.txt".By looking these,that repeating issue is related to this file handling codes(or not idk).Interesting thins is when I write swear word into server's chatbox,bot send only one "Please do not use this word ever" message.So How can i prevent bot not to repeat for many times?Thank you
import discord
from discord.ext import commands
intents = discord.Intents(messages=True, guilds=True, reactions=True, members=True,presences=True)
client = commands.Bot(command_prefix="!dc ", intents=intents)
#Below command gets repeated 7 times everytime.That number is same as the number of swear words in "Badwords.txt"
#client.command(aliases=["sayHi"])
async def greetings(ctx):
await ctx.send('Hi everyone')
#My purpose in the below codes is countering profanity
with open("Badwords.txt", "r", encoding="utf-8") as f:
word = f.read()
badwords = word.split(",")
#In the below event,bot sends message only 1 time for 1 message
#client.event
async def on_message(message):
msg = message.content
for x in badwords:
if x in msg:
await message.delete()
await message.channel.send("Please do not use this word ever")
else:
await client.process_commands(message)
client.run(Token)
I would take the await client.process_commands(message) out of the else statement. I have also moved the with open inside the on message event so everything a message is sent, it will open the file to check if the message contained a bad word.
import discord
from discord.ext import commands
intents = discord.Intents(messages=True, guilds=True, reactions=True, members=True,presences=True)
client = commands.Bot(command_prefix="!dc ", intents=intents)
#client.command(aliases=["sayHi"])
async def greetings(ctx):
await ctx.send('Hi everyone')
#client.event
async def on_message(message):
msg = message.content
with open("Badwords.txt", "r", encoding="utf-8") as f:
word = f.read()
badwords = word.split(",")
for x in badwords:
if x in msg:
await message.delete()
await message.channel.send("Please do not use this word ever")
else:
return
await client.process_commands(message)
client.run(Token)
await client.process_commands(message) was taken out of the else statement because, with your current code, the bot would only process the commands if the message did NOT contain a bad word. But we need it to process the commands every time a message is sent.

How to make bot reply to a mention discord.py

I'm making a discord bot and a problem that has come up for me is that the bot won't reply to the user, here is the code
#Code Imports
import discord
import random
from discord import message
from discord import channel
from discord.embeds import Embed
from discord.ext import commands
from discord.ext.commands.bot import Bot
from discord.message import Message
from apikeys import *
from discord import guild
from discord import emoji
from discord import *
from discord import ContentFilter
from discord import channel
from discord import client
#intents
intents=discord.Intents.default()
intents.members=True
#prefix
client=commands.Bot(command_prefix='!',intents=intents)
#Start
#client.event
async def on_ready():
for emoji in client.emojis:
print("Name:", emoji.name + ",", "ID:", emoji.id)
print('Bot is Online {0.user}'.format(client))
print("--------------------------------------------------------------------------------------------------------------------------------------------------------")
client.remove_command('help')
#Commands
#client.command()
async def work(ctx):
await ctx.send('use !war to get up the war menu')
emojigood = '\N{THUMBS UP SIGN}'
emojibad="\N{THUMBS DOWN SIGN}"
#client.command()
async def help(ctx):
embed=discord.Embed(title='Help', description='!war is currently under testing please do not complain about it', color=0x00000)
await ctx.send(embed=embed)
#client.command()
async def war(ctx):
embed = discord.Embed(title='War', description='You are starting a war, do you want to continue?', color=0x00000)
msg = await ctx.send(embed=embed)
await msg.add_reaction(emojigood)
await msg.add_reaction(emojibad)
def check(r, user):
return (r.emoji == emojigood or r.emoji == emojibad) and r.message == msg
#Checks whether the message is the same, and the emoji is one of the accepted ones, and returns either True or False
r, user = await client.wait_for('reaction_add',timeout=10 ,check=check)
#this is equivalent to a event listener within your command, it will stop there until a reaction that meets the requirements has been found
#(This won't block other commands and functions)
if r.emoji == emojigood:
embed = discord.Embed(title='War', description='Please now choose a country', color=0x00000)
await ctx.send(embed=embed)
prefix = "!" #insert your prefix
async def on_message(message):
if message.author == client.user:
return
if message.content == f'{prefix}war': #dont need to use this string, just illustrating the point
await message.channel.send("What country do you want to start a war with?")
def check(msg):
return msg.author == message.author and len(msg.role_mentions) > 0
msg = await client.wait_for('message', check=check)
role = msg.role_mentions[0]
channel = client.get_channel(849230881994047508)
await channel.send(f"{role.mention} {message.author} has declared war on you.")
client.run(token)
What's meant to happen:
Bot: Which role would you like to start a war with
User:#something
Bot:Send information to UN, 'War on #something'
I don't know how to make it see the role mention
You have a couple of issues, the way to make the code you're using function decently is to replace message.content with message.clean_content, however, 1. That will react to any message starting with # or a mention, which is probably not what you want, and 2. any message not beginning with the mention wouldn't work.
You say in your description that you're looking for role mentions, which is a different attribute, and you're looking to send a message, and wait for a response, so here's a piece of sample code that would solve those issues, assuming I'm interpreting your question correctly:
def check(msg):
return msg.author == message.author and len(msg.role_mentions) > 0
msg = await client.wait_for('message', check=check)
role = msg.role_mentions[0]
channel = client.get_channel(ID of the channel)
await channel.send(f"{role.mention} {message.author} has declared war on you."
If I misinterpreted any of what you wanted or you're not sure how some of it works, shoot me a comment and I'll do my best to explain!
Docs reference for slightly more complex objects used:
role_mentions,
wait_for(),

Command to spam something discord-bot

so basically I am trying to make a spam command for my discord bot, which takes in a custom message to spam. Here's the code:
#client.command(name='spam')
async def spam(ctx):
global stop
stop = 0
content = ctx.message.content[11:]
if ctx.author.guild_permissions.administrator or ctx.author.id in admins:
if lock == 1:
await ctx.send('Jesus bot is currently locked.')
elif lock == 0:
await ctx.send('Beginning spam..')
while not stop:
await ctx.send(content)
else:
await ctx.send('Sorry, but you do not have admin permissions in this server, or you are not a verified admin.')
For some reason, whenever I try to use this command, the bot doesn't respond. I'm not sure why this happens, and could use some help please.
Picture of bot not responding:
I have a spam command, but I only use it to mess around with my friends. I would not recommend using this as a public command, as you may get rate limited or banned for abuse or something like that. Anyway here is the code I have used for it.
#commands.command()
#commands.is_owner()
# If you want to use admin only, use this below
# #commands.has_permissions(administrator=True)
async def spam(self, ctx, amount, *, word):
int(amount)
await asyncio.sleep(2)
print(f"Starting to spam {word} in {ctx.guild.name}")
await ctx.message.delete()
await ctx.send(f"{ctx.author.mention}\nPlease note that this will clog up the bot's reaction time")
await asyncio.sleep(3)
count = 0
counting=True
while counting:
await ctx.send(word)
count = count + 1
if count == amount:
await asyncio.sleep(2)
await ctx.send("Spam complete")
print(Fore.GREEN + "Spam complete")
counting = False
At the top of your code, make sure you import asyncio as time.sleep will cause the whole bot to pause. Also the Fore.GREEN stuff is just colorama (import colorama).
Try using tasks instead of asyncio. It is made for such repetetive operations and it is easier and nicer because it is made by discord and is included in discord.ext. Something like this:
from discord.ext import tasks
#client.command(name='spam')
async def spam(ctx):
#get message and do all the ifs that you have there
spamLoop.start()
#client.command(name='stopSpam')
async def spamStop(ctx):
# stop the loop
spamLoop.cancel()
#tasks.loop(seconds=1)
async def spamLoop():
print("The message")
Actually quite a simple way of adding spam
import asyncio
#bot.command(name='spam', help= "Spam to your heart's delight")
async def spam(ctx, thing, amount):
count = 0
while count < int(amount):
await ctx.send(thing)
count += 1
if count < amount:
await asyncio.sleep(1)

Resources