Цифровая экосистема автономной модульной АЗС: FastAPI-бэкенд на чистом SQL, веб-интерфейс клиента, мониторинг состояния АЗС с системами безопасности с помощью датчиков и контроллера на базе esp32, дистанционное управление, вывод логов и телеметрии по MQTT.
- 📝 О проекте
- 📁 Структура репозитория
- 📐 Архитектура системы
- 💻 Backend ( WEB/backend )
- 🔧 Embedded / ESP32 (
Arduino/main) - 🌐 Frontend (
WEB/frontend) - 🔍 Распознавание номеров (
analiz_num) - 🚀 Запуск программы
- 🔐 Переменные окружения
- 🔗 API-эндпоинты
- 👥 Команда
- 📄 Лицензия
SAF (Smart AZS Future) — контейнерная автономная АЗС (40-футовый морской контейнер + солнечные панели + дизель-генератор) с цифровым ядром, которое связывает:
- клиентское веб-приложение;
- интерфейс мониторинга для работников: бэкенд-платформу учёта станций, ТРК, резервуаров, цен и транзакций;
- физический ESP32-контроллер на самой станции, который считывает показания датчиков, управляет работой АЗС (системы безопасности, ТРК, помещение КАЗС, генерация энергии);
- MQTT-канал телеметрии между железом и сервером.
Бэкенд написан на асинхронном FastAPI с чистым SQL через psycopg2 (без ORM) — это даёт полный контроль над транзакциями и SQL-запросами, что критично для сценариев вроде одновременной блокировки колонки несколькими клиентами.
future-AZS/
├── Arduino/
│ ├── main/
│ ├── main.ino # точка входа прошивки ESP32
│ ├── func.ino # опрос датчиков, отрисовка на дисплее
│ ├── func_wifi.ino # Wi-Fi/MQTT: подключение, телеметрия, приём команд
│ ├── config.h # пины, таймеры, структура SensorData
│ ├── Cl_timestamp.h # хелпер для NTP-времени
│ ├── foto.h # растровая заставка для TFT-дисплея
│ └── demo_secrets.h # шаблон для secrets.h (Wi-Fi/MQTT-доступы)
│ └── led/
│ └── led.ino #прошивка на контроллер ленты (arduino nano)
├── WEB/
│ ├── backend/
│ │ ├── main.py # точка входа FastAPI, подключение роутеров
│ │ ├── worker_mqtt.py # подписчик MQTT → запись показаний в БД
│ │ ├── init.sql # схема PostgreSQL
│ │ ├── routers/ # users, stations, pumps, prices, tanks, transactions, sensors
│ │ ├── schemas/schem.py # Pydantic-модели запросов
│ │ └── analiz_num/ # прототип распознавания гос. номеров
│ └── frontend/ # HTML/CSS/JS клиент
├── requirements.txt
└── LICENCE
┌────────────┐ HTTP/JSON ┌────────────────────┐
│ Frontend │ ───────────────────► │ FastAPI Core │
│ (JS/HTML) │ ◄─────────────────── │ API │
└────────────┘ └──────────┬─────────┘
│ psycopg2 (raw SQL)
▼
┌──────────────────┐
│ PostgreSQL │
│ (init.sql) │
└────────▲─────────┘
│ INSERT телеметрии
┌────────┴─────────┐
│ worker_mqtt.py │◄──── MQTT broker
└────────▲─────────┘ ▲
│ подписка │ публикация
│ BV/SAF/sensors │ телеметрии /
┌────────┴─────────┐ │ команды АЗС
│ ESP32 (Arduino) │────────┘
│ датчики + дисплей│
└──────────────────┘
Данные о станциях, пользователях и колонках хранятся в PostgreSQL и отдаются через REST API. Показания датчиков со станции идут отдельным потоком через MQTT: прошивка публикует JSON-телеметрию, worker_mqtt.py слушает топик и пишет её в таблицу sensors; обратная команда ((например) включить/выключить ТРК) публикуется бэкендом в топик конкретной колонки и обрабатывается контроллером как переключение реле.
Backend на FastAPI разбит на роутеры по сущностям:
| Файл | Префикс | Назначение |
|---|---|---|
routers/users.py |
/users |
Регистрация, логин, профиль клиента (телефон, email, госномер number_of_car) |
routers/stations.py |
/stations |
CRUD станций, привязка к региону, список ТРК на станции |
routers/pumps.py |
/pumps |
CRUD ТРК: статус (idle / dispensing / error), доступность is_active |
routers/prices.py |
/prices |
Цены на топливо по регионам, UPSERT через ON CONFLICT |
routers/tanks.py |
/tanks |
Резервуары/отсеки станции: остатки, температура, пополнение (refill) |
routers/transactions.py |
/transactions |
Оформление заказа на заправку |
routers/sensors.py |
/sensors |
Последние показания датчиков станции, отправка MQTT-команды на ТРК |
Модуль транзакций уже реализован: POST /transactions
- проверяет, что ТРК существует, активна (
is_active) и свободна (status = 'idle'); - находит цену топлива для региона станции;
- блокирует подходящий резервуар с помощью
SELECT ... FOR UPDATE, чтобы исключить гонку при параллельных заказах; - списывает литры из резервуара, переводит ТРК в статус
dispensing; - создаёт запись в
transactionsсо статусомprogressи считает итоговую стоимость; - фиксирует всё одной транзакцией (
connection.commit()/rollback()при ошибке —autocommit=False).
region → station → pumps, station → tanks, region → prices, pumps/users → transactions, users → loyalty_cards, station → uuid → sensors. Отдельного внимания заслуживают:
uuid— таблица привязки физического устройства (ESP32) к конкретной станции;sensors— сырые показания с контроллера: ток (electric_current), пламя, газ, влажность и температура воздуха, температура цистерны, уровень воды;loyalty_cards— карты лояльности с бонусным балансом и персональной скидкой (в API пока не задействованы — задел на будущее).
Прошивка контроллера станции — сердце физического слоя SAF. Устройство: ESP32, дисплей ST7735 (SPI), набор датчиков и одно силовое реле (в макете, далее выбранное оснащение).
Датчики и периферия (config.h):
| Пин | Датчик/модуль | Что измеряет |
|---|---|---|
DHT_PIN (14) |
DHT11 | температура и влажность воздуха |
DS18B20_PIN (26) |
DS18B20 (1-Wire) | температура топлива в цистерне |
FUEL_PIN (34) |
аналоговый уровнемер | уровень топлива (0–100 %) |
CURRENT_PIN (35) |
ACS712 | ток потребления (мА) |
FLAME_PIN (32) |
датчик пламени | пожарная безопасность |
GAZ_PIN (33) |
MQ-2 | загазованность |
RELAY_PIN (27) |
реле | включение/выключение ТРК |
TFT_CS/DC/RST/LED |
ST7735 TFT | локальный дисплей с показаниями в реальном времени |
Логика работы (main.ino, func.ino, func_wifi.ino):
- при старте контроллер подключается к Wi-Fi, синхронизирует время по NTP (
Cl_timestamp.h) и рисует стартовый экран с логотипом SAF; - каждую секунду (
DISPLAY_INTERVAL) опрашивает все датчики и обновляет значения на экране; - каждые 5 секунд (
MQTT_INTERVAL) собирает данные в JSON и публикует их в MQTT-топик (sendTelemetryMQTT) — именно этот пакет забираетworker_mqtt.pyна бэкенде; - подписан на топик
BV/SAF/{id}конкретной ТРК: получив сообщение"change", переключает состояние реле (callbackвfunc_wifi.ino) — это и есть физическое включение/выключение колонки по команде из API (POST /sensors/pumps/{pumps_id}); - отправляет команду
photoнаBV/SAF/cam/request, при получении этой команды esp32cam делает снимок с номером, который улетает на сервер; - получает, декодирует и выводит на экран номер с топика
BV/SAF/cam/response; - обрабатывает и переводит в нужный формат показания с датчиков с помощью фильтров и формул (напрмер для газа см.
func.ino(getGasPPM())).
Реальные Wi-Fi/MQTT-данные и UUID устройства не хранятся в репозитории — используется secrets.h (в .gitignore), а шаблон для заполнения лежит в demo_secrets.h. Перед прошивкой контроллера скопируйте его в secrets.h и подставьте свои значения.
Лёгкий клиент на чистых HTML/CSS/JS, без сборщиков и фреймворков:
config.js— задаётAPI_BASE(адрес бэкенда) и текущую станцию по умолчанию;api.js— тонкая обёртка надfetch(Api.get/post/put/del) с готовыми методами под все нужные эндпоинты (логин, список станций, ТРК станции, цены, оформление заказа);index.html/main.js— главный экран заправки;profile.html/profile.js— профиль пользователя;session.js— работа с сессией пользователя на клиенте.
здесь будут мокапы сайта
analiz_num/analiz_num.py — прототип модуля компьютерного зрения для автоматического распознавания госномера автомобиля: каскад Хаара (haarcascade_russian_plate_number.xml) находит рамку номера на фото, EasyOCR распознаёт текст на найденном фрагменте. Это заготовка под идею из бизнес-логики модуля пользователей — узнавать клиента по камере на въезде и предлагать его предполагаемый заказ. Также это система безопасности. Пока модуль работает автономно (планируется приём изображений с камер видеонаблюдения) и не подключён к FastAPI как эндпоинт.
cd WEB/backend
python -m venv venv
source venv/bin/activate # Linux/macOS
venv\Scripts\activate # Windows
pip install -r ../../requirements.txt
# создать .env (см. раздел ниже)
# поднять схему БД (PostgreSQL должен быть запущен и создана база)
psql -U <user> -d <database> -f init.sql
# запустить API
uvicorn main:app --reloadДокументация API (Swagger) будет доступна на http://127.0.0.1:8000/docs.
Отдельным процессом (например, во втором терминале) запускается воркер телеметрии:
python worker_mqtt.pyСтатические файлы из WEB/frontend можно открыть напрямую в браузере или раздать любым простым HTTP-сервером — предварительно проверьте API_BASE в config.js.
- Переименуете
demo_secrets.h→secrets.hи заполните реальными данными Wi-Fi/MQTT/UUID устройства. - Откройте
Arduino/main/main.inoв Arduino IDE / PlatformIO, установите библиотекиAdafruit_GFX,Adafruit_ST7735,DHT,ACS712,WiFi,PubSubClient,ArduinoJson,OneWire,DallasTemperature. - Откройте
Arduino/main/config.hи введите соответствующие пины ваших датчиков и нужные значения локальных переменных. - Выберите плату ESP32 и залейте прошивку.
Создайте файл WEB/backend/.env (в .gitignore, создаётся локально) и заполните его таким образом:
HOST=localhost
NAME_USER=postgres
PASSWORD=your_password
DATABASE=azs_db
MQTT_LOGIN=your_mqtt_login
MQTT_PASSWORD=your_mqtt_password
MQTT_ADDRESS=your_mqtt_broker_address
MQTT_PORT=1883
UUID=uuid_станции_для_чтения_последних_показаний| Модуль | Метод | Путь | Описание |
|---|---|---|---|
| Users | GET |
/users |
Список всех пользователей |
| Users | GET |
/users/{user_id} |
Один пользователь |
| Users | POST |
/users/register |
Регистрация (RETURNING id) |
| Users | PUT |
/users/{user_id} |
Частичное обновление профиля |
| Users | POST |
/users/login |
Аутентификация по email/паролю |
| Stations | GET |
/stations |
Список станций (join с регионом) |
| Stations | GET |
/stations/{id} |
Одна станция |
| Stations | POST |
/stations |
Создать станцию (регион создаётся при необходимости) |
| Stations | PUT |
/stations/{id} |
Обновить регион/адрес |
| Stations | DELETE |
/stations/{id} |
Удалить станцию |
| Stations | GET |
/stations/{id}/pumps |
Все ТРК станции |
| Pumps | GET |
/pumps/{id} |
Одна ТРК |
| Pumps | POST |
/pumps |
Создать ТРК |
| Pumps | PUT |
/pumps/{id} |
Обновить статус/активность |
| Pumps | DELETE |
/pumps/{id} |
Удалить ТРК |
| Prices | GET |
/prices/{station_id} |
Цены на топливо на станции (опц. фильтр fuel_type) |
| Prices | POST |
/prices |
Установить/обновить цену (UPSERT) |
| Prices | DELETE |
/prices/{region_id} |
Удалить цену по региону и типу топлива |
| Tanks | GET |
/tanks/station/{station_id} |
Резервуары станции с % заполнения |
| Tanks | PUT |
/tanks/{tank_id}/refill |
Пополнить резервуар |
| Tanks | POST |
/tanks |
Создать/обновить резервуар (UPSERT) |
| Transactions | POST |
/transactions |
Оформить заказ на заправку (списание топлива, блокировка ТРК) |
| Sensors | GET |
/sensors |
Последние показания датчиков станции |
| Sensors | POST |
/sensors/pumps/{pumps_id} |
Отправить MQTT-команду на переключение ТРК |
Воронин Сергей — embedded-разработчик
Есенин Константин — fullstak-разработчик
Веселов Василий — 3D-инженер
Рожков Егор — схемотехник
Дектеренко Евгения — эколог
Арынова Малика — дизайнер
Савельева Арина — экономист
Фадеев Дмитрий Владимирович
Косик Андрей Васильевич
Максимов Станислав Валерьевич
Проект распространяется на условиях All Rights Reserved — см. файл LICENCE. Копирование, модификация и использование кода (включая учебные и некоммерческие цели) без письменного согласия правообладателей запрещены.
© 2026 Esenin Konstantin, Voronin Sergey / SAF — Smart AZS Future.