🎯 ПРИНЦИПЫ АРХИТЕКТУРЫ
1. Стабильность превыше всего
- Эволюционное развитие без революционных изменений
- Приоритет качества кода над архитектурными экспериментами
- Тщательное тестирование перед внедрением изменений
2. Модульность и переиспользование
- Четкое разделение ответственности между модулями
- Минимизация циклических зависимостей
- Использование интерфейсов для абстракции
3. Производительность и эффективность
- Оптимизация использования памяти и Flash
- Эффективные алгоритмы обработки данных
- Минимизация накладных расходов
🔧 ОСНОВНЫЕ КОМПОНЕНТЫ
📡 СИСТЕМА ДАТЧИКОВ
🔌 Абстракция датчиков
// Файл: include/ISensor.h
class ISensor {
public:
virtual ~ISensor() = default;
virtual bool initialize() = 0;
virtual SensorData read() = 0;
virtual bool isConnected() const = 0;
virtual String getSensorInfo() const = 0;
};
🎭 Адаптеры датчиков
// Файл: src/modbus_sensor.h
class ModbusSensorAdapter : public ISensor {
private:
ModbusSensor* sensor;
public:
ModbusSensorAdapter(ModbusSensor* s) : sensor(s) {}
bool initialize() override {
return sensor->begin();
}
SensorData read() override {
return sensor->getData();
}
bool isConnected() const override {
return sensor->isConnected();
}
String getSensorInfo() const override {
return "Modbus Sensor v" + String(sensor->getVersion());
}
};
🧮 СИСТЕМА КОМПЕНСАЦИИ
✅ ИСПРАВЛЕННАЯ ДВУХЭТАПНАЯ КОМПЕНСАЦИЯ
// Файл: src/modbus_sensor.cpp
void applyCompensationIfEnabled(SensorData& d, const SoilProfile& profile) {
// ШАГ 1: Применяем калибровочную таблицу CSV (лабораторная поверка)
float tempCalibrated = CalibrationManager::applyCalibration(d.temperature, profile);
float humCalibrated = CalibrationManager::applyCalibration(d.humidity, profile);
float ecCalibrated = CalibrationManager::applyCalibration(d.ec, profile);
float phCalibrated = CalibrationManager::applyCalibration(d.ph, profile);
float nCalibrated = CalibrationManager::applyCalibration(d.nitrogen, profile);
float pCalibrated = CalibrationManager::applyCalibration(d.phosphorus, profile);
float kCalibrated = CalibrationManager::applyCalibration(d.potassium, profile);
// ШАГ 2: Применяем математическую компенсацию (температурная, влажностная)
float ec25 = ecCalibrated / (1.0f + 0.021f * (tempCalibrated - 25.0f));
d.ec = correctEC(ec25, tempCalibrated, humCalibrated, profile.soilType);
d.ph = correctPH(phCalibrated, tempCalibrated);
correctNPK(tempCalibrated, humCalibrated, d.nitrogen, d.phosphorus, d.potassium, profile.soilType);
}
🔧 Калибровочный менеджер
// Файл: src/calibration_manager.cpp
class CalibrationManager {
public:
// Применение калибровочной таблицы с линейной интерполяцией
static float applyCalibration(float rawValue, const CalibrationProfile& profile) {
if (!profile.isLoaded()) {
return rawValue; // Возвращаем исходное значение если таблица не загружена
}
// Поиск ближайших точек калибровки
CalibrationPoint lower, upper;
if (profile.findInterpolationPoints(rawValue, lower, upper)) {
// Линейная интерполяция
float ratio = (rawValue - lower.raw) / (upper.raw - lower.raw);
return lower.calibrated + ratio * (upper.calibrated - lower.calibrated);
}
return rawValue; // Вне диапазона калибровки
}
};
1️⃣ Модель Арчи - EC компенсация
float correctEC(float ec25, float temperature, float humidity, SoilType soilType) {
// Температурная компенсация (Archie, 1942)
float tempFactor = 1.0f + 0.021f * (temperature - 25.0f);
// Влажностная компенсация по модели Арчи
float porosity = getPorosity(soilType);
float archieCoeff = getArchieCoefficient(soilType);
float humFactor = pow(humidity / 100.0f, archieCoeff);
return ec25 * tempFactor * humFactor;
}
float getArchieCoefficient(SoilType soilType) {
switch (soilType) {
case SAND: return 0.15f; // Песок
case LOAM: return 0.30f; // Суглинок
case CLAY: return 0.45f; // Глина
case PEAT: return 0.10f; // Торф
case SANDY_PEAT: return 0.18f; // Песчано-торфяной
default: return 0.30f;
}
}
2️⃣ Уравнение Нернста - pH компенсация
float correctPH(float phRaw, float temperature) {
// Температурная поправка pH по уравнению Нернста
// dE/dT = -0.003 V/°C для pH электрода
return phRaw - 0.003f * (temperature - 25.0f);
}
3️⃣ FAO 56 + Eur. J. Soil Sci. - NPK компенсация
void correctNPK(float temperature, float humidity,
float& nitrogen, float& phosphorus, float& potassium,
SoilType soilType) {
// Температурная компенсация NPK
float tempFactor = 1.0f - 0.02f * (temperature - 25.0f);
// Влажностная компенсация по FAO 56
float humFactor = 1.0f + 0.05f * (humidity - 50.0f) / 50.0f;
// Применение компенсации
nitrogen *= tempFactor * humFactor;
phosphorus *= tempFactor * humFactor;
potassium *= tempFactor * humFactor;
}
🌐 ВЕБ-ИНТЕРФЕЙС
📱 Архитектура веб-интерфейса
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Web Browser │ │ ESP32 Web │ │ Data Storage │
│ (Frontend) │◄──►│ Server │◄──►│ (NVS/Flash) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Sensor Data │
│ Processing │
└─────────────────┘
🛣️ Маршрутизация
// Файл: src/web/routes_data.cpp
void setupDataRoutes() {
// Основные маршруты данных
server.on("/readings", HTTP_GET, handleReadings);
server.on("/intervals", HTTP_GET, handleIntervals);
server.on("/config_manager", HTTP_GET, handleConfigManager);
server.on("/updates", HTTP_GET, handleUpdates);
server.on("/service", HTTP_GET, handleService);
}