29 for (
size_t i = 0; i < length; i++)
31 if (buffer[i] < 0x10) hex_str +=
"0";
32 hex_str += String(buffer[i], HEX);
35 logDebug(
"%s%s", prefix, hex_str.c_str());
47 logSystem(
"=== ТЕСТИРОВАНИЕ SP3485E ===");
65 logSuccess(
"SP3485E DE/RE пины работают корректно");
69 logWarn(
"Нет ответа от SP3485E (это нормально без датчика)");
72 logSystem(
"=== ТЕСТ SP3485E ЗАВЕРШЕН ===");
111 uint16_t crc = 0xFFFF;
113 for (
size_t i = 0; i < length; i++)
115 crc ^= (uint16_t)data[i];
116 for (
int j = 0; j < 8; j++)
120 crc = (crc >> 1) ^ 0xA001;
155 logSensor(
"Запрос версии прошивки датчика...");
156 uint8_t result =
modbus.readHoldingRegisters(0x07, 1);
158 if (result ==
modbus.ku8MBSuccess)
160 uint16_t version =
modbus.getResponseBuffer(0);
161 logSuccess(
"Версия прошивки датчика: %d.%d", (version >> 8) & 0xFF, version & 0xFF);
166 logError(
"Ошибка чтения версии прошивки: %d", result);
175 if (result ==
modbus.ku8MBSuccess)
185 if (new_address < 1 || new_address > 247)
return false;
188 if (result ==
modbus.ku8MBSuccess)
192 modbus.begin(new_address, Serial2);
201 logSystem(
"=== ТЕСТ MODBUS СОЕДИНЕНИЯ ===");
207 logSystem(
"Тест 1: Проверка конфигурации пинов...");
212 logSuccess(
"Пины в правильном начальном состоянии (прием)");
216 logError(
"Неверное начальное состояние пинов");
221 logSystem(
"Тест 2: Проверка временных задержек...");
222 unsigned long start_time = micros();
224 unsigned long pre_delay = micros() - start_time;
226 start_time = micros();
228 unsigned long post_delay = micros() - start_time;
230 logSystem(
"Задержка preTransmission: %lu мкс", pre_delay);
231 logSystem(
"Задержка postTransmission: %lu мкс", post_delay);
233 if (pre_delay >= 50 && post_delay >= 50)
239 logWarn(
"Временные задержки меньше рекомендованных (50 мкс)");
243 logSystem(
"Тест 3: Проверка конфигурации UART...");
244 if (Serial2.baudRate() == 9600)
246 logSuccess(
"Скорость UART настроена правильно: 9600");
250 logError(
"Неверная скорость UART: %d", Serial2.baudRate());
255 logSystem(
"Тест 4: Чтение версии прошивки...");
256 uint8_t result =
modbus.readHoldingRegisters(0x00, 1);
257 if (result ==
modbus.ku8MBSuccess)
259 logSuccess(
"Успешно прочитан регистр версии");
263 logError(
"Ошибка чтения регистра версии: %02X", result);
267 logSuccess(
"=== ТЕСТ MODBUS ЗАВЕРШЕН УСПЕШНО ===");
284bool readSingleRegister(uint16_t reg_addr,
const char* reg_name,
float multiplier,
void* target,
bool is_float)
286 logDebug(
"Чтение %s (0x%04X)...", reg_name, reg_addr);
287 uint8_t result =
modbus.readHoldingRegisters(reg_addr, 1);
289 if (result ==
modbus.ku8MBSuccess)
291 uint16_t raw_value =
modbus.getResponseBuffer(0);
295 float* float_target =
static_cast<float*
>(target);
297 logDebug(
"%s: %.2f", reg_name, *float_target);
301 uint16_t* int_target =
static_cast<uint16_t*
>(target);
302 *int_target = raw_value;
303 logDebug(
"%s: %d", reg_name, *int_target);
309 logError(
"Ошибка чтения %s: %d", reg_name, result);
321 int success_count = 0;
335 return success_count;
344 int success_count = 0;
355 return success_count;
375 constexpr uint8_t WIN = 6;
376 static float buf[WIN] = {NAN};
377 static uint8_t idx = 0, filled = 0, persist = 0;
380 for (uint8_t i = 0; i < filled; ++i)
381 baseline = (buf[i] < baseline) ? buf[i] : baseline;
383 bool spike = (filled == WIN) &&
386 persist = spike ? persist + 1 : 0;
393 idx = (idx + 1) % WIN;
394 if (filled < WIN) ++filled;
401 if (!
config.flags.calibrationEnabled)
return;
405 switch (
config.soilProfile) {
423 float ec25 = ecCalibrated / (1.0f + 0.021f * (tempCalibrated - 25.0f));
424 d.
ec =
correctEC(ec25, tempCalibrated, humCalibrated, soil);
448 logError(
"❌ Не удалось прочитать один или несколько параметров");
466 logSuccess(
"✅ Все параметры прочитаны и валидны");
469 logWarn(
"⚠️ Данные прочитаны, но не прошли валидацию");
480 logSensor(
"Чтение всех параметров JXCT 7-в-1 датчика...");
489 bool total_success = (basic_success == 4) && (npk_success == 3);
497 return value * multiplier;
509 delayMicroseconds(50);
519 delayMicroseconds(50);
528 logSystem(
"🔥 Использую РАБОЧИЕ параметры: 9600 bps, 8N1, адрес 1");
529 logSystem(
"📊 Функция: периодическое чтение всех регистров датчика");
537 vTaskDelay(pdMS_TO_TICKS(
config.sensorReadInterval));
551 case ModbusMaster::ku8MBSuccess:
554 case ModbusMaster::ku8MBIllegalFunction:
555 logError(
"Modbus: Illegal Function Exception");
557 case ModbusMaster::ku8MBIllegalDataAddress:
558 logError(
"Modbus: Illegal Data Address Exception");
560 case ModbusMaster::ku8MBIllegalDataValue:
561 logError(
"Modbus: Illegal Data Value Exception");
563 case ModbusMaster::ku8MBSlaveDeviceFailure:
564 logError(
"Modbus: Slave Device Failure");
566 case ModbusMaster::ku8MBInvalidSlaveID:
567 logError(
"Modbus: Invalid Slave ID");
569 case ModbusMaster::ku8MBInvalidFunction:
570 logError(
"Modbus: Invalid Function");
572 case ModbusMaster::ku8MBResponseTimedOut:
573 logError(
"Modbus: Response Timed Out");
575 case ModbusMaster::ku8MBInvalidCRC:
579 logError(
"Modbus: Неизвестная ошибка %d", errNum);
591 for (
int i = 0; i < 15; i++)
603 DEBUG_PRINTLN(
"[MOVING_AVG] Буферы скользящего среднего инициализированы");
608 uint8_t window_size =
config.movingAverageWindow;
609 if (window_size < 5) window_size = 5;
610 if (window_size > 15) window_size = 15;
613 static float sum_temp = 0, sum_hum = 0, sum_ec = 0, sum_ph = 0, sum_n = 0, sum_p = 0, sum_k = 0;
641 if (effective_window >= 3 &&
config.filterAlgorithm == 0) {
644 data.
humidity = sum_hum / effective_window;
645 data.
ec = sum_ec / effective_window;
646 data.
ph = sum_ph / effective_window;
647 data.
nitrogen = sum_n / effective_window;
649 data.
potassium = sum_k / effective_window;
653 else if (effective_window >= 3) {
676 if (filled == 0)
return 0.0;
679 uint8_t elements_to_use = (filled < window_size) ? filled : window_size;
684 if (
config.filterAlgorithm == 1)
687 float temp_values[15];
688 for (uint8_t i = 0; i < elements_to_use; i++)
690 temp_values[i] = buffer[i];
694 for (uint8_t i = 0; i < elements_to_use - 1; i++)
696 for (uint8_t j = 0; j < elements_to_use - i - 1; j++)
698 if (temp_values[j] > temp_values[j + 1])
700 float temp = temp_values[j];
701 temp_values[j] = temp_values[j + 1];
702 temp_values[j + 1] = temp;
708 if (elements_to_use % 2 == 0)
710 return (temp_values[elements_to_use / 2 - 1] + temp_values[elements_to_use / 2]) / 2.0f;
714 return temp_values[elements_to_use / 2];
721 for (uint8_t i = 0; i < elements_to_use; i++)
725 return sum / elements_to_use;
#define DEBUG_PRINTF(fmt,...)
Централизованные константы системы JXCT.
constexpr int MODBUS_RX_PIN
constexpr unsigned long MODBUS_CACHE_TIMEOUT
constexpr int MODBUS_TX_PIN
constexpr int MODBUS_DE_PIN
constexpr int MODBUS_RE_PIN
void logDebug(const char *format,...)
void logWarn(const char *format,...)
void logPrintHeader(const char *title, const char *color)
void logSensor(const char *format,...)
void logSuccess(const char *format,...)
void logError(const char *format,...)
void logSystem(const char *format,...)
Система логгирования с красивым форматированием
void setupModbus()
Инициализация Modbus и SP3485E.
uint16_t calculateCRC16(uint8_t *data, size_t length)
void preTransmission()
Подготовка к передаче данных
void debugPrintBuffer(const char *prefix, uint8_t *buffer, size_t length)
void postTransmission()
Завершение передачи данных
bool readSingleRegister(uint16_t reg_addr, const char *reg_name, float multiplier, void *target, bool is_float)
Чтение одного регистра с обработкой ошибок
SensorData getSensorData()
static void applyCompensationIfEnabled(SensorData &d)
void startRealSensorTask()
void realSensorTask(void *pvParameters)
int readNPKParameters()
Чтение NPK параметров (азот, фосфор, калий)
bool readFirmwareVersion()
int readBasicParameters()
Чтение основных параметров (температура, влажность, pH, EC)
static unsigned long lastIrrigationTs
void finalizeSensorData(bool success)
Финализация данных датчика (валидация, кэширование, скользящее среднее)
static void saveRawSnapshot(SensorData &d)
static void updateIrrigationFlag(SensorData &d)
bool getCachedData(SensorData &data)
bool validateSensorData(SensorData &data)
float calculateMovingAverage(float *buffer, uint8_t window_size, uint8_t filled)
bool changeDeviceAddress(uint8_t new_address)
void testSP3485E()
Тестирование работы SP3485E.
float convertRegisterToFloat(uint16_t value, float multiplier)
void printModbusError(uint8_t errNum)
void initMovingAverageBuffers(SensorData &data)
bool testModbusConnection()
void addToMovingAverage(SensorData &data, float temp, float hum, float ec, float ph, float n, float p, float k)
#define REG_DEVICE_ADDRESS
#define REG_SOIL_MOISTURE
float applyCalibration(float rawValue, SoilProfile profile)
void correctNPK(float T, float theta, float &N, float &P, float &K, SoilType soil)
float correctPH(float phRaw, float T)
float correctEC(float ecRaw, float T, float theta, SoilType soil)
Алгоритмы коррекции показаний датчиков
unsigned long last_update