Датчик почвенной влажности soil-1 + второй релейный модуль под fan-1

По фото: у нас два одинаковых 2-канальных релейных модуля (не один) —
второй закрывает fan-1 по-настоящему (GPIO18), больше не "пока не куплено".

Добавлен soil-1: компараторный модуль почвенной влажности, читаем A0 через
ADC (GPIO34, input-only), публикуем sensor_type=soil_moisture в процентах.
Raw->% калибруется через SOIL_RAW_DRY/SOIL_RAW_WET в config.h — заводские
значения приблизительные, точную калибровку раньше сделать было нельзя (не
было физического доступа к датчику), нужно измерить на месте.

soil-1 в Postgres/Laravel платформы ещё не заведён (не трогаем
home_automatization) — телеметрия будет идти в ClickHouse, но в Laravel UI
устройство не появится до отдельной регистрации device_type/devices-записи.

Веб-интерфейс и /api/state дополнены полем "soil".
This commit is contained in:
2026-08-18 12:57:49 +05:00
parent 0456d4e447
commit 6a7d512b22
5 changed files with 127 additions and 44 deletions
+45 -12
View File
@@ -13,10 +13,25 @@ static bool hasReading = false;
static float lastTemperature = 0;
static float lastHumidity = 0;
static bool hasSoilReading = false;
static float lastSoilPercent = 0;
void telemetryBegin() {
dht.begin();
}
// Компараторный модуль почвенной влажности отдаёт на A0 сырое ADC-значение,
// которое УМЕНЬШАЕТСЯ с ростом влажности (суше — выше сопротивление датчика
// — выше напряжение на A0). SOIL_RAW_DRY/SOIL_RAW_WET в config.h — заводские
// значения-плейсхолдеры, откалибровать по месту (замерить raw на воздухе и
// в воде) через Serial-лог этой функции.
static float rawToSoilPercent(int raw) {
long percent = map(raw, SOIL_RAW_DRY, SOIL_RAW_WET, 0, 100);
if (percent < 0) percent = 0;
if (percent > 100) percent = 100;
return (float)percent;
}
void telemetryTick() {
unsigned long now = millis();
if (now - lastPublish < TELEMETRY_INTERVAL_MS && lastPublish != 0) {
@@ -32,21 +47,31 @@ void telemetryTick() {
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println("[telemetry] DHT22 read failed, skipping this cycle");
return;
Serial.println("[telemetry] DHT22 read failed, skipping this sensor this cycle");
} else {
lastTemperature = temperature;
lastHumidity = humidity;
hasReading = true;
mqttPublishTelemetry(DEVICE_ID_SENSOR, "temperature", temperature);
mqttPublishTelemetry(DEVICE_ID_SENSOR, "humidity", humidity);
Serial.print("[telemetry] temperature=");
Serial.print(temperature);
Serial.print(" humidity=");
Serial.println(humidity);
}
lastTemperature = temperature;
lastHumidity = humidity;
hasReading = true;
int soilRaw = analogRead(PIN_SOIL_MOISTURE);
lastSoilPercent = rawToSoilPercent(soilRaw);
hasSoilReading = true;
mqttPublishTelemetry(DEVICE_ID_SOIL, "soil_moisture", lastSoilPercent);
mqttPublishTelemetry(DEVICE_ID_SENSOR, "temperature", temperature);
mqttPublishTelemetry(DEVICE_ID_SENSOR, "humidity", humidity);
Serial.print("[telemetry] temperature=");
Serial.print(temperature);
Serial.print(" humidity=");
Serial.println(humidity);
Serial.print("[telemetry] soil_moisture=");
Serial.print(lastSoilPercent);
Serial.print("% (raw=");
Serial.print(soilRaw);
Serial.println(")");
}
bool telemetryGetLast(float& temperature, float& humidity) {
@@ -57,3 +82,11 @@ bool telemetryGetLast(float& temperature, float& humidity) {
humidity = lastHumidity;
return true;
}
bool telemetryGetLastSoil(float& percent) {
if (!hasSoilReading) {
return false;
}
percent = lastSoilPercent;
return true;
}