как обратиться в task к боту из другого task, а конкретно: отправить сообщение в ТГ по событию

есть бот, запускается как таск, есть функция, запускается тоже как отдельный таск. Эту конструкцию необходимо сохранить, тк. функция будет вызываться из другого файла .py

Вопрос: как из функции send_current() отправить сообщение в тг бот прм наступлении некоего события? понимаю что необходимо какимто образом передать хэндлеры при запуске таска: ioloop.create_task(send_current(Message, Bot))

в приведенном коде, если раскоментить любой bot.send.. и поставить свой user_id, вылетает ошибка: Bot.send_message() missing 1 required positional argument: 'text'

import asyncio
import logging
import sys
import os
from key import TOKEN


from aiogram import Bot, Dispatcher, Router, types
from aiogram.enums import ParseMode
from aiogram.types import Message
from aiogram.filters.command import Command


# All handlers should be attached to the Router (or Dispatcher)
dp = Dispatcher()


@dp.message(Command("hello"))
async def cmd_start(message: types.Message):
    await message.answer("Hello!")


async def send_current(message: types.Message, bot: Bot):

    print('start stream....')

    while True:
        await asyncio.sleep(1)
        try:
            if os.path.isfile('file.test'):
                print("file present! ")
                # await bot.send_message(message.from_user.id, f"Hello! {message.from_user.first_name} {message.from_user.id}!")
                # await bot.send_message(13, 'ello! !')
                # await bot.send_message(11, 'ello! !')

        except Exception as e:
            print(e)
            continue


async def main() -> None:
    bot = Bot(TOKEN, parse_mode=ParseMode.HTML)
    await dp.start_polling(bot)

if __name__ == "__main__":

    logging.basicConfig(level=logging.INFO, stream=sys.stdout)

ioloop = asyncio.get_event_loop()
tasks = [
    ioloop.create_task(send_current(Message, Bot)),
    ioloop.create_task(main())
]
ioloop.run_until_complete(asyncio.wait(tasks))
ioloop.close()

В данное время, трабла тут, как мне кажется... Но как правильно вызвать ioloop.create_task(send_current(Message, Bot), не понятно. введите сюда описание изображения что дает консоль при запуске отправка сообщения с явным указанием user_id


Ответы (1 шт):

Автор решения: Medvedev

Вам сама консоль указывает на причину возникшей проблемы. Bot.send_message() missing 1 required positional argument: 'text' - это значит, что send_message() не видит text

Укажите конкретно что чем является:

await bot.send_message(chat_id=message.chat.id, text=f"Hello! {message.from_user.first_name} {message.from_user.id}!")
await bot.send_message(chat_id=13, text='ello! !')
await bot.send_message(chat_id=11, text='ello! !')

UPD:

Объясняю ошибку: У вас запуск await bot.send_message происходит сразу после включения бота. Это так не работает, потому что: кому бот отправляет сообщение, если message.from_user.id ещё не получен от юзера?

Дополняю ответ с полностью исправленным кодом. Теперь задача создается после обращения пользователя к боту, в вашем случае после ввода команды /hello, после получения message бот корректно сможет извлечь необходимые аргументы и корректно отправить сообщение в нужный чат.

bot = Bot(TOKEN, parse_mode=ParseMode.HTML)
dp = Dispatcher()

task = [] # список для отслеживания созданных задач

@dp.message(Command("hello"))
async def cmd_start(message: types.Message):
    await message.answer("Hello!")
    user_id = message.from_user.id 
    # проверяем, есть ли user_id в списке, если нет, создаем задачу для пользователя
    if not user_id in task:
        asyncio.create_task(send_current(message, bot))
        # добавляем ид пользователя в список, после создания задачи
        task.append(user_id)


async def send_current(message: types.Message, bot: Bot):

    print('start stream....')

    while True:
        await asyncio.sleep(1)
        try:
            if os.path.isfile('file.test'):
                await bot.send_message(chat_id=message.chat.id, text=f"Hello! {message.from_user.first_name} {message.from_user.id}!")
                await bot.send_message(chat_id=13, text='ello! !')
                await bot.send_message(chat_id=11, text='ello! !')

        except Exception as e:
            print(e)
            continue


async def main() -> None:
    await dp.start_polling(bot)

if __name__ == '__main__': 
    asyncio.run(main())

UPD2:

Как и написал ранее, функция не будет работать, так как не может получить user_id, но можно сделать и так:

bot = Bot(TOKEN, parse_mode=ParseMode.HTML) # делаем глобальной

В функцию send_current(message: types.Message) передаем только значение message, тк bot - глобальный

И наконец, что бы сообщение корректно отправлялось, должны быть соблюдены 2 условия:

1 - user_id должен передаваться напрямую либо браться из БД, либо как сами придумаете

2 - Пользователь под этим user_id должен предварительно уже быть пользователем вашего бота, иначе никак, защита ТГ от спам рассылок.

# все остальные значения так же должны передаваться напрямую, получать через message нельзя
name = 'имя из БД'
id_from_user = 'ид из БД'
await bot.send_message(chat_id='9999999', f"Hello! {name} {id_from_user}!")) 

9999999 - замените вашим ИД

→ Ссылка