barometric_pressure.cpp
1 #include "barometric_pressure.h" 2 #include "registry.h" 3 #include <i2c.h> 4 5 #include <Arduino.h> 6 #include <Adafruit_LPS2X.h> 7 8 namespace { 9 10 constexpr uint16_t LPS25_INIT_SETTLE_MS = 200; 11 12 Adafruit_LPS25 lps; 13 bool available = false; 14 uint8_t detected_bus = 0; 15 16 } 17 18 bool sensors::barometric_pressure::initialize() { 19 available = false; 20 21 hardware::i2c::DiscoveredDevice dev = {}; 22 if (!hardware::i2c::findDevice(0x5D, &dev)) { 23 if (!hardware::i2c::findDevice(0x5C, &dev)) { 24 return false; 25 } 26 } 27 28 TwoWire *wire = (dev.bus == 0) ? &Wire : &Wire1; 29 if (!lps.begin_I2C(dev.address, wire)) { 30 return false; 31 } 32 33 lps.setDataRate(LPS25_RATE_25_HZ); 34 delay(LPS25_INIT_SETTLE_MS); 35 36 sensors_event_t discard_p, discard_t; 37 lps.getEvent(&discard_p, &discard_t); 38 39 detected_bus = dev.bus; 40 available = true; 41 Serial.printf("[pressure] LPS25 detected on bus %d at 0x%02X\n", dev.bus, dev.address); 42 43 sensors::registry::add({ 44 .kind = SensorKind::BarometricPressure, 45 .name = "Barometric Pressure", 46 .isAvailable = sensors::barometric_pressure::isAvailable, 47 .instanceCount = []() -> uint8_t { return 1; }, 48 .poll = [](uint8_t, void *out, size_t cap) -> bool { 49 if (cap < sizeof(BarometricPressureSensorData)) return false; 50 return sensors::barometric_pressure::access( 51 static_cast<BarometricPressureSensorData *>(out)); 52 }, 53 .data_size = sizeof(BarometricPressureSensorData), 54 }); 55 return true; 56 } 57 58 bool sensors::barometric_pressure::access(BarometricPressureSensorData *data) { 59 if (!data) return false; 60 if (!available) { 61 data->ok = false; 62 data->model = "none"; 63 return false; 64 } 65 66 sensors_event_t pressure_event, temp_event; 67 if (!lps.getEvent(&pressure_event, &temp_event)) { 68 data->ok = false; 69 data->model = "LPS25"; 70 return false; 71 } 72 73 data->pressure_hpa = pressure_event.pressure; 74 data->temperature_celsius = temp_event.temperature; 75 data->model = "LPS25"; 76 data->ok = true; 77 return true; 78 } 79 80 bool sensors::barometric_pressure::isAvailable() { 81 return available; 82 } 83 84 #ifdef PIO_UNIT_TESTING 85 86 #include <testing/utils.h> 87 88 namespace sensors::barometric_pressure { void test(void); } 89 90 static void test_pressure_init(void) { 91 WHEN("the barometric pressure module is initialized"); 92 hardware::i2c::initialize(); 93 if (!sensors::barometric_pressure::initialize()) { 94 TEST_IGNORE_MESSAGE("no LPS25 sensor connected"); 95 return; 96 } 97 TEST_ASSERT_TRUE_MESSAGE(sensors::barometric_pressure::isAvailable(), 98 "device: LPS25 not available after initialization"); 99 } 100 101 static void test_pressure_read(void) { 102 GIVEN("the LPS25 sensor is available"); 103 WHEN("a reading is taken"); 104 if (!sensors::barometric_pressure::isAvailable()) { 105 TEST_IGNORE_MESSAGE("no LPS25 sensor available"); 106 return; 107 } 108 delay(500); 109 BarometricPressureSensorData data = {}; 110 bool ok = sensors::barometric_pressure::access(&data); 111 if (!ok) { 112 TEST_IGNORE_MESSAGE("reading not ready yet"); 113 return; 114 } 115 char msg[64]; 116 snprintf(msg, sizeof(msg), "LPS25: %.2f hPa, %.2f C", data.pressure_hpa, data.temperature_celsius); 117 TEST_MESSAGE(msg); 118 TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(data.pressure_hpa, 119 "device: pressure reading is NaN or Inf"); 120 TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(data.temperature_celsius, 121 "device: temperature reading is NaN or Inf"); 122 TEST_ASSERT_GREATER_THAN_FLOAT_MESSAGE(900.0f, data.pressure_hpa, 123 "device: pressure below 900 hPa — sensor may be faulty"); 124 TEST_ASSERT_LESS_THAN_FLOAT_MESSAGE(1100.0f, data.pressure_hpa, 125 "device: pressure above 1100 hPa — sensor may be faulty"); 126 } 127 128 void sensors::barometric_pressure::test(void) { 129 MODULE("Barometric Pressure"); 130 RUN_TEST(test_pressure_init); 131 RUN_TEST(test_pressure_read); 132 } 133 134 #endif