Всем привет!
Если на работе я — инженер-проектировщик, то дома я — садовод-огородник, и при большом количестве разных зеленых друзей на подоконнике — теряешься в расписании полива. Поэтому я решила написать бота для растений — мы напишем простого, но полезного помощника: Telegram-бота, который будет напоминать, когда поливать цветы.
В этой части мы реализуем диалоговую логику. А во второй части — подключим базу данных и настроим уведомления.
К концу первой части у вас будет бот, который:
здоровается по имени
принимает команду /add_plant
ведёт диалог: «Как зовут растение? Когда поливал(а)? Через сколько дней снова?»
Что нам понадобится?
Что |
Для чего |
Telegram |
Где будет жить бот |
Python 3.12+ |
Язык программирования |
Любой текстовый редактор (Блокнот, VS Code) |
Чтобы писать код |
Шаг 1. Создаём бота через — и делаем его по-настоящему своим
Telegram → @BotFather → Start → Список команд

Нажимаем /newbot. Выбираем имя и username.
Важно про username!
Должен оканчиваться на bot (можно _bot, Bot, BOT — регистр не важен)
Только латинские буквы, цифры и подчёркивания
Максимум 32 символа
Должен быть уникальным во всём Telegram

Получаем токен и прячем его. (Токен мы никому не передаем, не выкладываем на Git (вообще не выкладываем в интернет)).
Если всё прошло успешно, BotFather отправит:

Опционально, но очень рекомендуется: настраиваем «личность» бота
После создания бота BotFather предложит команды для настройки. Я хочу чтобы бот выглядел красиво и был настоящим помощником.


Я же заполнила описание, поставила аватарку. Теперь вот выглядит миленько.
Переходим в наш бот, нажимаем /start и видим, что бот неактивен, а теперь займемся его оживлением.
Шаг 2. Устанавливаем Python (можно пропустить, если он уже установлен)
Переходим в cmd и вводим python --version. Если выдает ошибку - то нам нужно сначала скачать и установить Python себе на компьютер.
Выбираем актуальную версию с официального сайта https://www.python.org/downloads/windows/ , скачиваем и устанавливаем.
ВАЖНО! На первом экране установки поставьте галочку:
✅ Add Python to PATH (Это позволит запускать python из командной строки)
Возвращаемся в cmd вводим python --version и должны получить версию (может быть другая)

И надо не забыть установить библиотеку python-telegram-botpip install python-telegram-bot
Команда должна (и обязана) совершиться без ошибки.
Шаг 3. Пишем простой код для бота
As for me, самая тяжелая часть.
Создаем папку проекта, где будут храниться файлы нашего бота. Создать внутри папки файл, например, bot.py. В файле bot.py пишем код:
Подробнее про использование используемых библиотек, все четко и по делу - https://docs-python.ru/packages/biblioteka-python-telegram-bot-python/
#Импортируем нужные инструменты из библиотеки python-telegram-bot, в данном случае это Update:
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
#СЮДА ВСТАВЛЯЕТСЯ ТОКЕН, КОТОРЫЙ ВЫДАЛ
#никогда никому не показывайте этот токен ! (тот, который ниже - ненастоящий)
BOT_TOKEN = "876543234567898765432"
#функция, которая срабатывает, когда пользователь пишет /start
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
#достаём информацию о пользователе
effective_user — это объект, содержащий: имя, ID, username и т.д. (берём имя из профиля Telegram)
user = update.effective_user
name = user.first_name or "друг"
#Если имя не указано - то напишем друг)
#отправляем ответное сообщение прямо в чат с пользователем
await update.message.reply_text(
f"Привет, {name}! ?\n"
"Я — бот для ухода за цветами.\n"
"Рада тебя видеть!"
)
#Функция, которая запускает бота
def main():
app = Application.builder().token(BOT_TOKEN).build()
#говорим боту: «Когда кто-то напишет /start — вызови функцию start»
app.add_handler(CommandHandler("start", start))
#это сообщение выводится в терминале (чисто прикормка для тревожника,
#чтобы мы знали что код отработал без ошибок и не зациклился)
print("Бот запущен! Напиши ему в Telegram.")
#запускаем цикл - бот сидит и ждет новых сообщений
run_polling()
app.run_polling()
#эта строчка стандартная «заглушка»
if name == "main":
main()
Сохраняем файл, переходим в cmd и вводим C:\Users\admin\flower_bot>python bot.py

Переходим в Telegram и отправляем /start

Шаг 4. Добавляем диалог: «Расскажи мне о своём растении»
Структура кода будет такая:
Пользователь: /add_plant
↓
Бот: → вызывает ask_name (entry_point)
↓
Пользователь: "Фикус"
↓
Бот: сохраняет 'Фикус' → спрашивает дату → переходит в состояние DATE
↓
Пользователь: "15.11.2025"
↓
Бот: сохраняет дату → спрашивает интервал → переходит в INTERVAL
↓
Пользователь: "7"
↓
Бот: выводит сводку → очищает данные → завершает диалог
Нам нужно добавить новые функции, чтобы бот "разговаривал" с нами
Спрашиваем название растения: ask_name
Назначение: Получить и сохранить название растения от пользователя. Вызывается после команды /add_plant.
Что делает:
• Берёт текст сообщения (название растения) из update.message.text.
• Сохраняет его во временное хранилище пользователя context.user_data['name'].
• Отправляет сообщение с запросом даты.
• Возвращает состояние DATE → бот "переключается" на следующий шаг диалога. async def ask_name(update, context): context.user_data['name'] = update.message.text # ← записываем в "блокнот" пользователя
await update.message.reply_text("? Дата последнего полива?")
return DATE # → переходим к шагу DATE
Спрашиваем дату последнего полива: ask_date
Назначение: Получить и сохранить дату последнего полива.
Вызывается когда бот находится в состоянии DATE (после ask_name). Что делает:
• Берёт текст сообщения (дату) без валидации
• Сохраняет в context.user_data['date'].
• Запрашивает интервал полива.
• Возвращает состояние INTERVAL → переход к финальному шагу. async def ask_date(update, context): context.user_data['date'] = update.message.text ← сохраняем дату как строку await update.message.reply_text("⏳ Интервал полива (дней)?") return INTERVAL → переходим к шагу INTERVAL
Спрашиваем интервал полива: ask_interval
Назначение: Получить интервал и завершить диалог, показав сводку.
Вызывается, когда бот состоянии INTERVAL (после ask_date).
Что делает:
• Извлекает все данные из "блокнота": name, date, и текущее сообщение — интервал.
• Формирует и отправляет итоговое сообщение с подтверждением.
• Очищает user_data
• Возвращает ConversationHandler.END — диалог закрывается. async def ask_interval(update, context):
Берём всё, что накопили:
name = context.user_data['name'] # название date = context.user_data['date'] # дата interval = update.message.text # интервал
Подтверждаем добавление:await update.message.reply_text(
f"✅ {name} добавлено!\n"
f"Последний полив: {date}\n"
f"Интервал: {interval} дней"
)
В итоге у нас получается такой код:
from telegram import Update
from telegram.ext import (
Application,
CommandHandler,
MessageHandler,
filters,
ContextTypes,
ConversationHandler,
)
# ТОКЕН!
BOT_TOKEN = "838765567890-098765456789098765"
# Этапы диалога (состояния ConversationHandler)
# Используем константы для читаемости: 0 → NAME, 1 → DATE, 2 → INTERVAL
NAME, DATE, INTERVAL = range(3)
# === /start — приветствие и инструкция ===
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(
"Привет! ?\n Чтобы добавить растение — отправь /add_plant"
)
# === /add_plant — запуск диалога ===
async def add_plant_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Бот переходит в состояние NAME - ожидаем название растения.
"""
await update.message.reply_text("? Название растения?")
return NAME # → переключаемся на этап NAME
# === Этап NAME: получаем и проверяем название ===
async def ask_name(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Обрабатывает ввод названия растения.
- Проверяем, что строка не пустая (минимальная валидация).
- Сохраняем в user_data — временный контекст пользователя.
- Переходим к следующему этапу — DATE.
"""
plant_name = update.message.text.strip()
if not plant_name:
await update.message.reply_text("❌ Введи название.")
return NAME # остаёмся на том же этапе (повторный запрос)
context.user_data['plant_name'] = plant_name # ← сохраняем в "блокнот"
await update.message.reply_text("? Дата последнего полива (ДД.ММ.ГГГГ)?")
return DATE # → переходим к этапу DATE
# === Этап DATE: парсим дату ===
async def ask_date(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Ожидаем дату в строгом формате ДД.ММ.ГГГГ.
- Используем datetime.strptime — защита от некорректного ввода.
- При ошибке — просим повторить, не выходя из состояния.
- Сохраняем в ISO-формате (YYYY-MM-DD)
"""
try:
from datetime import datetime
# Парсим дату по шаблону — строгая валидация
last_watered = datetime.strptime(update.message.text.strip(), "%d.%m.%Y").date()
# Сохраняем как строку в формате ISO (2025-11-19) — стандарт для хранения
context.user_data['last_watered'] = last_watered.isoformat()
await update.message.reply_text("⏳ Интервал полива (дней)?")
return INTERVAL # → переходим к финальному этапу
except ValueError:
# Если формат неверный — не прерываем диалог, а просим исправить
await update.message.reply_text("❌ Формат: ДД.ММ.ГГГГ")
return DATE # остаёмся в состоянии DATE
# === Этап INTERVAL: проверяем и завершаем ===
async def ask_interval(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Получаем интервал полива.
- Проверяем, что это целое положительное число.
- Формируем итоговое сообщение.
- Очищаем user_data — хорошая практика (избегаем "утечек" между сессиями).
- Завершаем диалог.
"""
try:
interval = int(update.message.text.strip())
if interval <= 0:
raise ValueError # чтобы обработать как ошибку ввода
# Достаём ранее сохранённые данные
plant_name = context.user_data['plant_name']
last_watered = context.user_data['last_watered']
# Подтверждаем добавление (в реальном проекте — здесь вызов БД)
await update.message.reply_text(
f"✅ {plant_name} добавлено!\n"
f"Последний полив: {last_watered}\n"
f"Интервал: {interval} дней"
)
# Чистим временные данные
context.user_data.clear()
return ConversationHandler.END # ← диалог завершён
except ValueError:
await update.message.reply_text("❌ Введи целое число > 0.")
return INTERVAL # повторный запрос, не выходя из состояния
# === Основная функция: сборка и запуск бота ===
def main():
"""Собирает приложение и регистрирует обработчики."""
app = Application.builder().token(BOT_TOKEN).build()
# Диалоговый обработчик: управляет состояниями и переходами
conv_handler = ConversationHandler(
# Диалог начинается с команды /add_plant
entry_points=[CommandHandler("add_plant", add_plant_start)],
# Что происходит на каждом этапе
states={
NAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, ask_name)],
DATE: [MessageHandler(filters.TEXT & ~filters.COMMAND, ask_date)],
INTERVAL: [MessageHandler(filters.TEXT & ~filters.COMMAND, ask_interval)],
},
# Диалог изолирован по пользователям (по умолчанию True)
per_user=True,
)
# Регистрируем обработчики команд и диалогов
app.add_handler(CommandHandler("start", start))
app.add_handler(conv_handler)
print("✅ Бот с диалогом запущен!")
app.run_polling()
if __name__ == "__main__":
main()
Переходим в Телеграмм и начинаем общаться с нашим ботом

В этой статье мы собрали «скелет» Telegram-бота: от регистрации в BotFather до рабочего диалогового интерфейса. Реализовали пошаговое добавление растения.
Мы реализовали пошаговое добавление растения через ConversationHandler: бот последовательно запрашивает название, дату последнего полива и интервал, сохраняя промежуточные данные в context.user_data.
Что дальше?
Во второй части мы:
подключим базу данных, чтобы данные не исчезали после перезапуска;
добавим команду
/list— чтобы пользователь видел все свои растения;и настроим напоминания о поливе через JobQueue
Kahelman
„безумие и отвага» не проще/ лучше было бы сделать автоматическую систему полива и забыть о проблеме?