Senzory¶
Na této stránce připojujete dva senzory a výstup jejich dat na portál. Nejprve SHT31 (klima skříně), pak termistor (teplota ohřívače). Toto je krok „získáme data" před přidáním logiky řízení.
Princip práce s jádrem je jednoduchý: váš kód v loop() zapisuje čerstvá čtení do polí s_link.telemetry.* a fasáda je automaticky publikuje do cloudu každých telemetryPeriodMs z Config. Ruční vyvolání publikace není potřebné.
Telemetrická pole¶
Pro naši skříň se používají tři pole (index [0] — první a jediná komora):
| Pole | Co ukládá | Příznak v Config |
|---|---|---|
s_link.telemetry.airTempC[0] |
teplota vzduchu, °C | hasAirTemp |
s_link.telemetry.airHumidityPct[0] |
vlhkost vzduchu, % | hasAirHumidity |
s_link.telemetry.heaterTempC[0] |
teplota ohřívače, °C | hasHeaterTemp |
Tyto tři příznaky se zapínají právě zde, v Config (viz úplný výpis na konci kapitoly). Příznak říká portálu a aplikaci, že zařízení takový senzor má: bez něj se buňka na kartě neobjeví.
Pravidlo: kód senzoru nesmí blokovat loop()¶
Fasáda idryer-core obsluhuje Wi-Fi a MQTT ve stejném loop(). Proto při čtení senzorů nelze volat delay() — pauza přeruší síťovou relaci. Senzor se dotazuje podle časovače a hotová hodnota se jednoduše přečte. Hotové ovladače z ekosystému jsou již takto uspořádány.
Krok 1. SHT31: klima skříně¶
Psát ovladač SHT31 od nuly není potřebné — gotová třída Sht31ClimateSensor leží v příkladu této kapitoly, example/09-cabinet. Používá knihovnu robtillaart/SHT31 a čte senzor bez blokování.
-
Přidejte knihovnu SHT31 do
lib_depssvéhoplatformio.ini: -
Zkopírujte do své složky
src/čtyři soubory ovladače: -
Připojte senzor přes I2C (viz Schéma zapojení) a přečtěte jej v
src/main.cpp:
#include <Wire.h>
#include <iDryer.h>
#include "Sht31ClimateSensor.h"
static Sht31ClimateSensor s_climate(&Wire);
static bool s_climateOk = false;
void setup() {
Serial.begin(115200);
Wire.begin(8, 9); // SDA, SCL — vývody vaší desky
s_climateOk = s_climate.begin(); // automaticky najde adresu 0x44 nebo 0x45
s_link.begin();
// Zařízení bylo na portálu odpojeno: smazat tajný klíč, čekat na nové spárování.
s_link.onCommand("revoke", [](JsonObjectConst) { s_link.handleRevoke(); });
}
void loop() {
s_link.loop();
if (s_climateOk) {
s_climate.tick(millis());
SensorReading r = s_climate.get();
if (r.ok) {
s_link.telemetry.airTempC[0] = r.temperature;
s_link.telemetry.airHumidityPct[0] = r.humidity;
}
}
}
Jeden snímek hodnot vrací ovladač strukturou SensorReading ze sensor_reading.h:
struct SensorReading {
float temperature = NAN; // °C, NAN pokud není hodnota
float humidity = NAN; // % RH, NAN pokud není hodnota
float pressure = NAN; // hPa, pro budoucí senzory
uint32_t ts_ms = 0; // millis() v okamžiku čtení
bool ok = false; // true, pokud jsou teplota i vlhkost platné
int err = 0; // kód chyby, 0 — bez chyby
};
Po nahrání do zařízení se na portálu objeví teplota a vlhkost skříně — toto je první zpětná vazba ze zařízení.
Krok 2. Termistor: teplota ohřívače¶
Gotové třídy termistoru pro ESP32 nemám, takže si jej napíšeme přímo v src/main.cpp. Termistor je připojen na výstup ADC přes měnič napětí (viz Schéma zapojení): kontrolér měří napětí v středním bodě, odtud se vypočítá odpor termistoru a poté teplota.
#include <math.h>
static const int THERM_PIN = 2; // výstup ADC
static const float SERIES_R = 4700.0f; // rezistor děliče, Ω
static const float NOMINAL_R = 100000.0f; // odpor termistoru na 25 °C, Ω
static const float NOMINAL_T = 25.0f; // °C
static const float BETA = 3950.0f; // B-koeficient z technické dokumentace termistoru
// Vrací teplotu ohřívače v °C.
static float readHeaterTempC() {
int raw = analogRead(THERM_PIN); // 0..4095 na ESP32
float v = (float)raw / 4095.0f; // podíl z plné stupnice
float r = SERIES_R * (1.0f - v) / v; // odpor termistoru, Ω
// Steinhart-Hartova rovnice ve tvaru B-parametru — viz Wikipedii:
// https://en.wikipedia.org/wiki/Steinhart%E2%80%93Hart_equation
float tK = 1.0f / (1.0f / (NOMINAL_T + 273.15f) + logf(r / NOMINAL_R) / BETA);
return tK - 273.15f;
}
V loop() zapisujte výsledek do telemetrie vedle čtení SHT31:
Toto je zjednodušené čtení — upravte parametry pro váš termistor
Konstanty NOMINAL_R a BETA závisí na konkrétním termistoru — vezměte je z jeho technické dokumentace (běžný domácí termistor je Generic 3950, 100 kΩ). Vzorec děliče odpovídá schématu z Schématu zapojení: termistor na 3.3V, rezistor na GND. Při jiném rozložení se vzorec změní. ADC na ESP32 je nelineární, takže pro přesná měření se čtení kalibrují — v sériových kontrolérech iDryer se k tomu používá tabulka termistoru (knihovna Thermistor).
Ověření termistoru multimetrem — Ověření termistoru.
Krok 3. Nemáte senzory po ruce? Demo režim¶
Projít cestu až ke kartě lze i bez železa: hodnoty spočítá model skříně. Zkopírujte soubor demo_sensors.h ze stejného příkladu:
a přidejte do platformio.ini příznak sestavení:
Obě větve jsou schované za jednou funkcí a loop() neví, odkud hodnoty přišly:
static void readSensors() {
#ifdef DEMO_SENSORS
demoSensors(s_link.telemetry);
#else
// čtení SHT31 a termistoru — jako výše
#endif
}
Model se chová jako skutečná skříň: místnost pomalu kolísá kolem 24 °C, zapnutý ohřívač vzduch ohřívá, vypnutý jej nechá vychladnout, při ohřevu klesá vlhkost. Výkon ohřevu model čte z telemetrie, takže logika z kapitoly Řízení ohřevu vidí odezvu a hystereze funguje. Snímky obrazovky v této části vznikly právě takto.
Pro provozní zařízení se příznak nenastavuje: pak se sestaví větev se skutečnými senzory.
Úplný src/main.cpp po této kapitole¶
Níže je celý soubor dohromady. Nové řádky ve srovnání s předchozí kapitolou jsou označeny // ← kapitola 5; zbytek se nezměnil.
Co bylo — src/main.cpp po kapitole 4
#include <iDryer.h>
static const iDryer::Config CFG = {
.deviceType = iDryer::DeviceType::Unknown, // vlastní zařízení: kartu sestavuje manifest
.unitsCount = 1,
.telemetryPeriodMs = 5000,
.statusPeriodMs = 10000,
.hardwareVersion = "1.0",
.firmwareVersion = "0.1.0",
.model = "DIY Storage Cabinet",
};
static iDryer::Link s_link(CFG);
void setup() {
Serial.begin(115200);
s_link.begin();
// Zařízení bylo na portálu odpojeno: smazat tajný klíč, čekat na nové spárování.
s_link.onCommand("revoke", [](JsonObjectConst) { s_link.handleRevoke(); });
}
void loop() {
s_link.loop();
}
#include <iDryer.h>
#include <Wire.h> // ← kapitola 5
#include <math.h> // ← kapitola 5
#include "Sht31ClimateSensor.h" // ← kapitola 5
#include "demo_sensors.h" // ← kapitola 5: hodnoty bez senzorů (-DDEMO_SENSORS=1)
static const iDryer::Config CFG = {
.deviceType = iDryer::DeviceType::Unknown, // vlastní zařízení: kartu sestavuje manifest
.unitsCount = 1,
.hasAirTemp = true, // ← kapitola 5
.hasAirHumidity = true, // ← kapitola 5
.hasHeaterTemp = true, // ← kapitola 5
.telemetryPeriodMs = 5000,
.statusPeriodMs = 10000,
.hardwareVersion = "1.0",
.firmwareVersion = "0.1.0",
.model = "DIY Storage Cabinet",
};
static iDryer::Link s_link(CFG);
// ← kapitola 5: senzor klimatu SHT31
static Sht31ClimateSensor s_climate(&Wire);
static bool s_climateOk = false;
// ← kapitola 5: termistor ohřívače
static const int THERM_PIN = 2;
static const float SERIES_R = 4700.0f;
static const float NOMINAL_R = 100000.0f;
static const float NOMINAL_T = 25.0f;
static const float BETA = 3950.0f;
static float readHeaterTempC() {
int raw = analogRead(THERM_PIN);
float v = (float)raw / 4095.0f;
float r = SERIES_R * (1.0f - v) / v;
float tK = 1.0f / (1.0f / (NOMINAL_T + 273.15f) + logf(r / NOMINAL_R) / BETA);
return tK - 273.15f;
}
// ← kapitola 5: senzory nebo, s -DDEMO_SENSORS=1, model skříně
static void readSensors() {
#ifdef DEMO_SENSORS
demoSensors(s_link.telemetry);
#else
if (s_climateOk) {
s_climate.tick(millis());
SensorReading r = s_climate.get();
if (r.ok) {
s_link.telemetry.airTempC[0] = r.temperature;
s_link.telemetry.airHumidityPct[0] = r.humidity;
}
}
s_link.telemetry.heaterTempC[0] = readHeaterTempC();
#endif
}
void setup() {
Serial.begin(115200);
Wire.begin(8, 9); // ← kapitola 5 (SDA, SCL — vývody vaší desky)
s_climateOk = s_climate.begin(); // ← kapitola 5
s_link.begin();
// Zařízení bylo na portálu odpojeno: smazat tajný klíč, čekat na nové spárování.
s_link.onCommand("revoke", [](JsonObjectConst) { s_link.handleRevoke(); });
}
void loop() {
s_link.loop();
readSensors(); // ← kapitola 5
}
Ověření výsledku¶
Hodnoty na kartě a graf telemetrie. Teplota ohřívače jde na grafu samostatnou čarou. Menu dole na stránce je zatím prázdné — tím se zabývá další kapitola.
Po tomto kroku by se na portálu měly zobrazovat tři hodnoty:
- teplota vzduchu ve skříni;
- vlhkost ve skříni;
- teplota ohřívače.
Pokud se čtení „pohybují" nebo jsou zřejmě nesprávná:
- zkontrolujte společné uzemění a rozvedení (rušení od silných vedení) — Chyby zapojení;
- zkontrolujte hodnotu rezistoru děliče a typ termistoru;
- ujistěte se, že SHT31 reaguje na I2C (správná adresa a vedení).
Diagnostika „senzor ukazuje nesmysly" — Ověření termistoru a Běžné chyby.
Co dál¶
Máme data ze senzorů. Teď popíšeme nastavení zařízení (cílová teplota, hystereze) v Menu z YAML, aby je bylo možné měnit z portálu a ukládat v paměti.