/ firmware / tests / ntc_formula.rs
ntc_formula.rs
  1  //! `describe("NTC formula (pure logic)")`
  2  //!
  3  //! Pure-logic unit tests for the Steinhart–Hart-style β-coefficient
  4  //! conversion the firmware uses to derive a temperature from a measured
  5  //! ADC voltage on a 10 kΩ NTC thermistor in a fixed-resistor divider.
  6  
  7  #![no_std]
  8  #![no_main]
  9  
 10  #[path = "common/mod.rs"]
 11  mod common;
 12  
 13  use defmt::info;
 14  
 15  use common::Device;
 16  
 17  const ADC_REFERENCE_VOLTAGE_VOLTS: f32 = 3.3;
 18  const NTC_BETA_COEFFICIENT: f32 = 3988.0;
 19  const REFERENCE_TEMPERATURE_KELVIN: f32 = 298.15;
 20  const NOMINAL_RESISTOR_OHMS: f32 = 10_000.0;
 21  
 22  fn calculate_ntc_temperature_celsius_from_voltage_measured(
 23      measured_voltage_volts: f32,
 24  ) -> f32 {
 25      let voltage_fraction = measured_voltage_volts / ADC_REFERENCE_VOLTAGE_VOLTS;
 26      let thermistor_resistance_ratio =
 27          ((voltage_fraction * NOMINAL_RESISTOR_OHMS) / (1.0 - voltage_fraction))
 28              * (1.0 / NOMINAL_RESISTOR_OHMS);
 29      let inverse_temperature_kelvin = (1.0 / REFERENCE_TEMPERATURE_KELVIN)
 30          + (1.0 / NTC_BETA_COEFFICIENT) * libm::logf(thermistor_resistance_ratio);
 31      (1.0 / inverse_temperature_kelvin) - 273.15
 32  }
 33  
 34  esp_bootloader_esp_idf::esp_app_desc!();
 35  
 36  #[cfg(test)]
 37  #[embedded_test::setup]
 38  fn setup() {
 39      rtt_target::rtt_init_defmt!();
 40  }
 41  
 42  #[cfg(test)]
 43  #[embedded_test::tests(default_timeout = 5, executor = esp_rtos::embassy::Executor::new())]
 44  mod tests {
 45      use super::*;
 46  
 47      #[init]
 48      fn init() -> Device {
 49          info!("=== NTC formula (pure logic) — describe block ===");
 50          common::setup::boot_device()
 51      }
 52  
 53      /// `it("user reads a room-temperature reading at half-rail voltage")`
 54      #[test]
 55      async fn user_reads_room_temperature_at_half_rail_voltage(
 56          _device: Device,
 57      ) -> Result<(), &'static str> {
 58          let measured_voltage_volts = 1.65;
 59          let calculated_temperature_celsius =
 60              calculate_ntc_temperature_celsius_from_voltage_measured(measured_voltage_volts);
 61  
 62          info!(
 63              "1.65V on the divider → {=f32} °C",
 64              calculated_temperature_celsius
 65          );
 66  
 67          if calculated_temperature_celsius < 20.0 {
 68              return Err("device: half-rail voltage produced a temperature below room range");
 69          }
 70          if calculated_temperature_celsius > 30.0 {
 71              return Err("device: half-rail voltage produced a temperature above room range");
 72          }
 73          Ok(())
 74      }
 75  
 76      /// `it("user reads a cold reading at low voltage")`
 77      #[test]
 78      async fn user_reads_cold_temperature_at_low_voltage(
 79          _device: Device,
 80      ) -> Result<(), &'static str> {
 81          let measured_voltage_volts = 0.66;
 82          let calculated_temperature_celsius =
 83              calculate_ntc_temperature_celsius_from_voltage_measured(measured_voltage_volts);
 84  
 85          info!(
 86              "0.66V on the divider → {=f32} °C",
 87              calculated_temperature_celsius
 88          );
 89  
 90          if calculated_temperature_celsius >= 20.0 {
 91              return Err("device: low-side voltage should report a cold temperature");
 92          }
 93          Ok(())
 94      }
 95  
 96      /// `it("user reads a hot reading at high voltage")`
 97      #[test]
 98      async fn user_reads_hot_temperature_at_high_voltage(
 99          _device: Device,
100      ) -> Result<(), &'static str> {
101          let measured_voltage_volts = 2.64;
102          let calculated_temperature_celsius =
103              calculate_ntc_temperature_celsius_from_voltage_measured(measured_voltage_volts);
104  
105          info!(
106              "2.64V on the divider → {=f32} °C",
107              calculated_temperature_celsius
108          );
109  
110          if calculated_temperature_celsius <= 30.0 {
111              return Err("device: high-side voltage should report a hot temperature");
112          }
113          Ok(())
114      }
115  }