diff --git a/Cargo.lock b/Cargo.lock
index b6d03cebbdea8dfbabf1b0bfeeb05442ddb885e1..bcfdfd57ee5843db8c65140de41934690007f73b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -65,6 +65,15 @@ dependencies = [
  "wyz",
 ]
 
+[[package]]
+name = "bme280"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32c139eaf2284d0c91a25f61d84dd326444cace86cb0371f45d71d2d055ba432"
+dependencies = [
+ "embedded-hal 0.2.7",
+]
+
 [[package]]
 name = "byteorder"
 version = "1.5.0"
@@ -76,6 +85,7 @@ name = "cats-mobile-transceiver-mainboard"
 version = "0.2.1"
 dependencies = [
  "arrayvec",
+ "bme280",
  "cortex-m",
  "cortex-m-rt",
  "cortex-m-rtic",
diff --git a/Cargo.toml b/Cargo.toml
index 6412f1dc6c3ea68c827d14ae04e770ec99faa79d..1891060b95e03fcdb5fb4e3be1e75d04d741defd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,3 +36,4 @@ num-traits = { version = "0.2.17", default-features = false, features = ["libm"]
 rand = { version = "0.8", default-features = false, features = ["small_rng"] }
 postcard = "1.0.8"
 serde = { version = "1.0.196", default-features = false, features = ["derive"] }
+bme280 = { version = "0.3", default-features = false }
diff --git a/src/main.rs b/src/main.rs
index 1037e276a39b9cd4b4b91ffca25077130f01a822..1a68693bad98b20f23fee11fa779b5e9de234e05 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,6 +24,7 @@ mod app {
     use core::fmt::Write;
 
     use arrayvec::ArrayString;
+    use bme280::i2c::BME280;
     use cortex_m::singleton;
     use hal::{
         adc::{config::AdcConfig, Adc},
@@ -42,7 +43,12 @@ mod app {
         packet::Packet,
         whisker::{Gps, NodeInfoBuilder, Route},
     };
-    use stm32f4xx_hal as hal;
+    use stm32f4xx_hal::{
+        self as hal,
+        i2c::I2c,
+        pac::{I2C1, TIM11},
+        timer::Delay,
+    };
     use systick_monotonic::{fugit::Instant, ExtU64, Systick};
     use usb_device::prelude::*;
 
@@ -73,6 +79,8 @@ mod app {
     #[monotonic(binds = SysTick, default = true)]
     type MyMono = Systick<{ SYS_TICK_FREQ }>;
 
+    pub type MyBme280 = BME280<I2c<I2C1>, Delay<TIM11, 1000>>;
+
     #[local]
     struct Local {
         green: gpio::Pin<'B', 15, gpio::Output>,
@@ -91,6 +99,7 @@ mod app {
         radio: Option<RadioManager<'static>>,
         gps: GpsModule,
         volt_meter: VoltMeter,
+        bme280: MyBme280,
 
         usb_dev: UsbDevice<'static, UsbBusType>,
         shell: Shell,
@@ -191,6 +200,19 @@ mod app {
         .with_u8_data();
         gps_serial.listen(serial::Event::Rxne);
 
+        // Set up BME280
+        let scl = gpiob.pb8;
+        let sda = gpiob.pb9;
+        let i2c = I2c::new(
+            dp.I2C1,
+            (scl, sda),
+            hal::i2c::Mode::standard(100.kHz()),
+            &clocks,
+        );
+
+        let mut bme280 = BME280::new_primary(i2c, dp.TIM11.delay_ms(&clocks));
+        let _ = bme280.init();
+
         // Setup USB
         static mut EP_MEMORY: [u32; 1024] = [0; 1024];
         static mut USB_BUS: Option<usb_device::bus::UsbBusAllocator<UsbBusType>> = None;
@@ -258,6 +280,7 @@ mod app {
                 radio,
                 gps: GpsModule::new(),
                 volt_meter,
+                bme280,
 
                 usb_dev,
                 shell,
@@ -292,7 +315,7 @@ mod app {
         }
     }
 
-    #[task(priority = 2, local = [buf, bootup_time], shared = [red, radio, gps, config, status, volt_meter])]
+    #[task(priority = 2, local = [buf, bootup_time], shared = [red, radio, gps, config, status, volt_meter, bme280])]
     fn transmit_position(mut ctx: transmit_position::Context) {
         let mut config = ctx.shared.config;
         let (black_hole, transmit_period_seconds) =
@@ -331,6 +354,14 @@ mod app {
                 .to_secs()
                 .try_into()
                 .unwrap_or(0);
+            let (temperature, pressure, humidity) = ctx.shared.bme280.lock(|b| match b.measure() {
+                Ok(o) => (o.temperature, o.pressure, o.humidity),
+                Err(_) => {
+                    let _ = b.init(); // hail mary attempt
+
+                    (0.0, 0.0, 0.0)
+                }
+            });
 
             let mut info_builder = NodeInfoBuilder::default()
                 .hardware_id(HARDWARE_ID)
@@ -348,7 +379,12 @@ mod app {
                 .unwrap();
 
                 let mut buf: ArrayString<64> = ArrayString::new();
-                write!(&mut buf, "{} {} {}", sensors[0], sensors[1], sensors[2]).unwrap();
+                write!(
+                    &mut buf,
+                    "{} {} {} {} {} {}",
+                    sensors[0], sensors[1], sensors[2], temperature, pressure, humidity
+                )
+                .unwrap();
                 cats.add_comment(&buf).unwrap();
 
                 cats.add_route(Route::new(config.max_hops)).unwrap();
@@ -467,17 +503,18 @@ mod app {
         }
     }
 
-    #[task(binds=OTG_FS, priority = 2, local=[flash], shared=[usb_dev, shell, volt_meter])]
+    #[task(binds=OTG_FS, priority = 2, local=[flash], shared=[usb_dev, shell, volt_meter,bme280])]
     fn usb_fs(cx: usb_fs::Context) {
         let usb_fs::SharedResources {
             mut usb_dev,
             mut shell,
             mut volt_meter,
+            mut bme280,
         } = cx.shared;
 
         (&mut usb_dev, &mut shell).lock(|usb_dev, shell| {
             while usb_dev.poll(&mut [shell.ushell.get_serial_mut()]) {
-                shell.poll(cx.local.flash, &mut volt_meter);
+                shell.poll(cx.local.flash, &mut volt_meter, &mut bme280);
             }
         });
     }
diff --git a/src/shell.rs b/src/shell.rs
index dc9fab44e4a69881d1ee96c02a7d0723a4edcd3c..1a9c5960881b5bf051171ce361225ba4cd523fe4 100644
--- a/src/shell.rs
+++ b/src/shell.rs
@@ -10,6 +10,7 @@ use usbd_serial::SerialPort;
 use ushell::{autocomplete::StaticAutocomplete, history::LRUHistory, Input, ShellError, UShell};
 
 use crate::{
+    app::MyBme280,
     config::{BlackHoleSetting, Config, Frequency, GpsSetting, Maybe, MaybeBlackHole},
     voltage::VoltMeter,
 };
@@ -54,7 +55,12 @@ impl Shell {
         Self { ushell, config }
     }
 
-    pub fn poll<V: Mutex<T = VoltMeter>>(&mut self, flash: &mut LockedFlash, volt_meter: &mut V) {
+    pub fn poll<V: Mutex<T = VoltMeter>, B: Mutex<T = MyBme280>>(
+        &mut self,
+        flash: &mut LockedFlash,
+        volt_meter: &mut V,
+        bme280: &mut B,
+    ) {
         loop {
             let ushell = &mut self.ushell;
             match ushell.poll() {
@@ -266,6 +272,19 @@ impl Shell {
                             )
                             .ok();
                         }
+                        "bme280" => match bme280.lock(|b| b.measure()) {
+                            Ok(m) => {
+                                write!(
+                                    ushell,
+                                    "\r\nTemperature: {} deg C\r\nPressure: {} pascals\r\nHumidity: {}%\r\n",
+                                    m.temperature, m.pressure, m.humidity
+                                ).ok();
+                            }
+                            Err(e) => {
+                                write!(ushell, "Could not communicate with the bme280: {:?}", e)
+                                    .ok();
+                            }
+                        },
                         "help" => {
                             write!(ushell, "{}", HELP_TEXT).ok();
                         }