Стриминг местоположения в реальном времени в телеграм
В Телеграм пользователь может поделиться местоположением выбрав точку на карте либо транслировать местоположение в реальном времени. как реализовать получение для выбранной точки в телеграмм боте на aiogram и запись широты и долготы выбранных точек в базу данных, либо отправку обратно пользователю и любые действия с ними я знаю. Вот соотвествующий код Код для отправки просто выбранной точки на карте.
import asyncio
import logging
import sys
import sqlite3
from aiogram import Bot, Dispatcher, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.storage.redis import RedisStorage
from aiogram.filters import CommandStart
from config import TOKEN
# Инициализация бота
bot = Bot(TOKEN, parse_mode="HTML")
# Определение состояний бота
class Form(StatesGroup):
WaitForAddress = State()
# Создание роутера
from aiogram.dispatcher.router import Router
form_router = Router()
# Инициализация базы данных
def init_db():
conn = sqlite3.connect('locations.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS locations (
user_id INTEGER,
latitude REAL,
longitude REAL
)
''')
conn.commit()
conn.close()
# Сохранение местоположения в базу данных
def save_location(user_id, latitude, longitude):
conn = sqlite3.connect('locations.db')
cursor = conn.cursor()
cursor.execute('INSERT INTO locations (user_id, latitude, longitude) VALUES (?, ?, ?)', (user_id, latitude, longitude))
conn.commit()
conn.close()
# Создание функции-обработчика для команды /start
@form_router.message(CommandStart())
async def command_start_handler(message: types.Message, state: FSMContext) -> None:
await message.answer(
"Добро пожаловать! ?\n\n"
"Чтобы продолжить, пожалуйста, отправьте ваше местоположение."
)
await state.set_state(Form.WaitForAddress)
# Обработчик для получения местоположения
@form_router.message(Form.WaitForAddress)
async def location_handler(message: types.Message, state: FSMContext):
if message.content_type == types.ContentType.LOCATION:
user_location = message.location
latitude = user_location.latitude
longitude = user_location.longitude
save_location(message.from_user.id, latitude, longitude)
await message.answer(f"Координаты сохранены: Широта {latitude}, Долгота {longitude}")
await state.clear()
else:
await message.answer("Пожалуйста, отправьте ваше местоположение.")
async def main() -> None:
init_db()
storage = RedisStorage.from_url('redis://localhost:6379/0')
dp = Dispatcher(storage=storage)
dp.include_router(form_router)
await dp.start_polling(bot)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
asyncio.run(main())
А вот код с попыткой отлавливать местоположение в реальном времени.Но получилось что в базу данных записывается только начальная точка.
import asyncio
import logging
import sys
import sqlite3
from datetime import datetime, timedelta
from aiogram import Bot, Dispatcher, types
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.storage.redis import RedisStorage
from aiogram.filters import CommandStart
from config import TOKEN # Импорт токена бота из отдельного файла конфигурации
# Инициализация бота с указанным токеном и форматом сообщений HTML
bot = Bot(TOKEN, parse_mode="HTML")
# Определение состояний для управления разными этапами диалога с пользователем
class Form(StatesGroup):
WaitForAddress = State() # Ожидание местоположения от пользователя
LiveLocation = State() # Режим отслеживания живого местоположения
# Создание роутера для обработки входящих сообщений
from aiogram.dispatcher.router import Router
form_router = Router()
# Функция инициализации базы данных
def init_db():
conn = sqlite3.connect('locations.db') # Создание или подключение к базе данных
cursor = conn.cursor()
# Создание таблицы для хранения местоположений, если она еще не существует
cursor.execute('''
CREATE TABLE IF NOT EXISTS locations (
user_id INTEGER,
latitude REAL,
longitude REAL
)
''')
conn.commit() # Применение изменений в базе данных
conn.close() # Закрытие соединения с базой данных
# Функция для сохранения местоположения пользователя в базе данных
def save_location(user_id, latitude, longitude):
conn = sqlite3.connect('locations.db')
cursor = conn.cursor()
# Вставка новой записи с местоположением пользователя
cursor.execute('INSERT INTO locations (user_id, latitude, longitude) VALUES (?, ?, ?)', (user_id, latitude, longitude))
conn.commit()
conn.close()
# Функция для получения последнего известного местоположения пользователя
def get_last_location(user_id):
conn = sqlite3.connect('locations.db')
cursor = conn.cursor()
# Запрос последнего местоположения пользователя из базы данных
cursor.execute('SELECT latitude, longitude FROM locations WHERE user_id = ?', (user_id,))
result = cursor.fetchone()
conn.close()
return result
# Словарь для хранения времени последнего обновления местоположения для каждого пользователя
last_update_time = {}
# Асинхронная функция для периодической отправки обновлений местоположения пользователя
async def periodic_update(user_id):
while user_id in last_update_time:
now = datetime.now()
# Проверка, прошло ли 30 секунд с последнего обновления
if now - last_update_time[user_id] >= timedelta(seconds=30):
location = get_last_location(user_id)
if location:
# Отправка сообщения пользователю с текущими координатами
await bot.send_message(user_id, f"Текущие координаты: Широта {location[0]}, Долгота {location[1]}")
last_update_time[user_id] = now
await asyncio.sleep(10) # Пауза между проверками
# Функция обновления местоположения в базе данных
def update_location(user_id, latitude, longitude):
last_location = get_last_location(user_id)
# Обновление записи только при изменении координат
if not last_location or (last_location[0] != latitude or last_location[1] != longitude):
conn = sqlite3.connect('locations.db')
cursor = conn.cursor()
cursor.execute('UPDATE locations SET latitude = ?, longitude = ? WHERE user_id = ?', (latitude, longitude, user_id))
conn.commit()
conn.close()
print(f"Обновленные координаты пользователя {user_id}: Широта {latitude}, Долгота {longitude}")
else:
print(f"Координаты пользователя {user_id} не изменились.")
last_update_time[user_id] = datetime.now()
asyncio.create_task(periodic_update(user_id))
# Обработчик команды /start
@form_router.message(CommandStart())
async def command_start_handler(message: types.Message, state: FSMContext) -> None:
await message.answer(
"Добро пожаловать! ?\n\n"
"Чтобы продолжить, пожалуйста, отправьте ваше местоположение."
)
await state.set_state(Form.WaitForAddress) # Установка состояния ожидания местоположения
# Обработчик для получения местоположения от пользователя
@form_router.message(Form.WaitForAddress)
async def location_handler(message: types.Message, state: FSMContext):
if message.content_type == types.ContentType.LOCATION:
user_location = message.location
latitude = user_location.latitude
longitude = user_location.longitude
if user_location.live_period:
save_location(message.from_user.id, latitude, longitude)
await state.set_state(Form.LiveLocation) # Переход в режим отслеживания живого местоположения
await message.answer("Начало трансляции местоположения.")
else:
save_location(message.from_user.id, latitude, longitude)
await message.answer(f"Координаты сохранены: Широта {latitude}, Долгота {longitude}")
await state.clear() # Очистка состояния
# Обработчик для живого местоположения
@form_router.message(Form.LiveLocation)
async def live_location_handler(message: types.Message, state: FSMContext):
if message.content_type == types.ContentType.LOCATION:
user_location = message.location
latitude = user_location.latitude
longitude = user_location.longitude
update_location(message.from_user.id, latitude, longitude)
if not user_location.live_period:
await state.set_state(Form.WaitForAddress) # Возврат в режим ожидания местоположения
await message.answer("Трансляция местоположения завершена.")
# Главная функция для запуска бота
async def main() -> None:
init_db()
storage = RedisStorage.from_url('redis://localhost:6379/0')
dp = Dispatcher(storage=storage)
dp.include_router(form_router)
await dp.start_polling(bot)
# Точка входа в программу
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
asyncio.run(main())