diff --git a/Documentation/pycardium/bme680.rst b/Documentation/pycardium/bme680.rst
new file mode 100644
index 0000000000000000000000000000000000000000..aa937fdfbf699cf59a9b7acfe17470ffde0c6748
--- /dev/null
+++ b/Documentation/pycardium/bme680.rst
@@ -0,0 +1,17 @@
+``bme680`` - 4-in-1 Sensor
+==========================
+
+.. py:function:: bme680.init()
+
+   Before being able to read data from the sensor, you have to call init().
+
+.. py:function:: bme680.get_data()
+
+   Does a single measurement to get environmental data.
+
+   :return: Tuple containing ``temperature`` (°C), ``humidity`` (% r.h.), 
+   ``pressure`` (hPa) and ``gas resistance`` (Ohm).
+
+.. py:function:: bme680.deinit()
+
+   De-Initializes the sensor.
\ No newline at end of file
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 69899aaeb9b7e52a848b61b3e9451dd75f14708e..b576662965726dcf83caefcb3287e87c791da319 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -107,6 +107,10 @@ typedef _Bool bool;
 #define API_PERSONAL_STATE_GET     0xc1
 #define API_PERSONAL_STATE_IS_PERSISTENT 0xc2
 
+#define API_BME680_INIT            0xD0
+#define API_BME680_DEINIT          0xD1
+#define API_BME680_GET_DATA        0xD2
+
 /* clang-format on */
 
 typedef uint32_t api_int_id_t;
@@ -673,6 +677,66 @@ API(API_LEDS_SET_GAMMA_TABLE, void epic_leds_set_gamma_table(
  */
 API(API_LEDS_CLEAR_ALL, void epic_leds_clear_all(uint8_t r, uint8_t g, uint8_t b));
 
+/**
+ * BME680
+ * ======
+ */
+
+/**
+ * BME680 Sensor Data
+ */
+struct bme680_sensor_data {
+	/** Temperature in degree celsius */
+	float temperature;
+	/** Humidity in % relative humidity */
+	float humidity;
+	/** Pressure in hPa */
+	float pressure;
+	/** Gas resistance in Ohms */
+	float gas_resistance;
+};
+
+/**
+ * Initialize the BM680 sensor.
+ *
+ * :return: 0 on success or ``-Exxx`` on error.  The following
+ *     errors might occur:
+ *
+ *     - ``-EFAULT``:  On NULL-pointer.
+ *     - ``-EINVAL``:  Invalid configuration.
+ *     - ``-EIO``:  Communication with the device failed.
+ *     - ``-ENODEV``:  Device was not found.
+ */
+API(API_BME680_INIT, int epic_bme680_init());
+
+/**
+ * De-Initialize the BM680 sensor.
+ *
+ * :return: 0 on success or ``-Exxx`` on error.  The following
+ *     errors might occur:
+ *
+ *     - ``-EFAULT``:  On NULL-pointer.
+ *     - ``-EINVAL``:  Invalid configuration.
+ *     - ``-EIO``:  Communication with the device failed.
+ *     - ``-ENODEV``:  Device was not found.
+ */
+API(API_BME680_DEINIT, int epic_bme680_deinit());
+
+/**
+ * Get the current BME680 data.
+ *
+ * :param data: Where to store the environmental data.
+ * :return: 0 on success or ``-Exxx`` on error.  The following
+ *     errors might occur:
+ *
+ *     - ``-EFAULT``:  On NULL-pointer.
+ *     - ``-EINVAL``:  Sensor not initialized.
+ *     - ``-EIO``:  Communication with the device failed.
+ *     - ``-ENODEV``:  Device was not found.
+ */
+API(API_BME680_GET_DATA,
+	int epic_bme680_read_sensors(struct bme680_sensor_data *data));
+
 /**
  * Personal State
  * ==============
diff --git a/epicardium/modules/bme680.c b/epicardium/modules/bme680.c
new file mode 100644
index 0000000000000000000000000000000000000000..bdc603d699fe5c4a63e8d29c0dfa79d6e810b66b
--- /dev/null
+++ b/epicardium/modules/bme680.c
@@ -0,0 +1,138 @@
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include "bme680.h"
+#include "bosch.h"
+#include "card10.h"
+
+#include "epicardium.h"
+#include "modules.h"
+#include "modules/log.h"
+
+#define HEATR_TEMP 320
+#define HEATR_DUR 150
+
+static bool initialized;
+static struct bme680_dev bme;
+
+static int convert_error(int8_t error)
+{
+	switch (error) {
+	case BME680_E_NULL_PTR:
+		return EFAULT;
+	case BME680_E_COM_FAIL:
+		return EIO;
+	case BME680_E_DEV_NOT_FOUND:
+		return ENODEV;
+	case BME680_E_INVALID_LENGTH:
+		return EINVAL;
+	default:
+		return 1;
+	}
+}
+
+int epic_bme680_init()
+{
+	int8_t result = BME680_OK;
+
+	if (__builtin_expect(!initialized, 0)) {
+		bme.dev_id   = BME680_I2C_ADDR_PRIMARY;
+		bme.intf     = BME680_I2C_INTF;
+		bme.read     = card10_bosch_i2c_read;
+		bme.write    = card10_bosch_i2c_write;
+		bme.delay_ms = card10_bosch_delay;
+		/* amb_temp can be set to 25 prior to configuring the gas sensor
+     * or by performing a few temperature readings without operating the gas sensor.
+     */
+		bme.amb_temp = 25;
+
+		result = bme680_init(&bme);
+		if (result != BME680_OK) {
+			LOG_ERR("bme680", "bme680_init error: %d\n", result);
+			return -convert_error(result);
+		}
+
+		/* Select the power mode */
+		/* Must be set before writing the sensor configuration */
+		bme.power_mode = BME680_FORCED_MODE;
+
+		/* Set the temperature, pressure and humidity settings */
+		bme.tph_sett.os_hum  = BME680_OS_2X;
+		bme.tph_sett.os_pres = BME680_OS_4X;
+		bme.tph_sett.os_temp = BME680_OS_8X;
+		bme.tph_sett.filter  = BME680_FILTER_SIZE_3;
+
+		/* Set the remaining gas sensor settings and link the heating profile */
+		bme.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
+		/* Create a ramp heat waveform in 3 steps */
+		bme.gas_sett.heatr_temp = HEATR_TEMP; /* degree Celsius */
+		bme.gas_sett.heatr_dur  = HEATR_DUR;  /* milliseconds */
+
+		/* Set the required sensor settings needed */
+		uint16_t settings_sel = BME680_OST_SEL | BME680_OSP_SEL |
+					BME680_OSH_SEL | BME680_FILTER_SEL |
+					BME680_GAS_SENSOR_SEL;
+
+		result = bme680_set_sensor_settings(settings_sel, &bme);
+		if (result != BME680_OK) {
+			LOG_ERR("bme680",
+				"bme680_set_sensor_settings error: %d\n",
+				result);
+			return -convert_error(result);
+		}
+
+		initialized = true;
+	}
+	return 0;
+}
+
+int epic_bme680_deinit()
+{
+	int8_t result = BME680_OK;
+
+	result = bme680_soft_reset(&bme);
+	if (result != BME680_OK) {
+		LOG_ERR("bme680", "bme680_soft_reset error: %d\n", result);
+		return -convert_error(result);
+	}
+
+	initialized = false;
+	return 0;
+}
+
+int epic_bme680_read_sensors(struct bme680_sensor_data *data)
+{
+	int8_t result = BME680_OK;
+
+	if (!initialized) {
+		LOG_ERR("bme680", "bme680 sensor not initialized");
+		return -EINVAL;
+	}
+
+	uint16_t profile_dur = 0;
+	bme680_get_profile_dur(&profile_dur, &bme);
+
+	result = bme680_set_sensor_mode(&bme); /* Trigger a measurement */
+	if (result != BME680_OK) {
+		LOG_ERR("bme680", "bme680_set_sensor_mode error: %d\n", result);
+		return -convert_error(result);
+	}
+
+	vTaskDelay(pdMS_TO_TICKS(
+		profile_dur)); /* Wait for the measurement to complete */
+
+	struct bme680_field_data raw_data;
+	result = bme680_get_sensor_data(&raw_data, &bme);
+	if (result != BME680_OK) {
+		LOG_ERR("bme680", "bme680_get_sensor_data error: %d\n", result);
+		return -convert_error(result);
+	}
+
+	data->temperature    = raw_data.temperature / 100.0l;
+	data->humidity       = raw_data.humidity / 1000.0l;
+	data->pressure       = raw_data.pressure / 100.0l;
+	data->gas_resistance = raw_data.gas_resistance;
+
+	return 0;
+}
diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c
index 5cb95dc286d3262504886d210580bdc9f9b12263..44ae9ab75dd0f9dd7223f40837db38e6b2d47e08 100644
--- a/epicardium/modules/hardware.c
+++ b/epicardium/modules/hardware.c
@@ -231,5 +231,10 @@ int hardware_reset(void)
 	 */
 	display_init_slim();
 
+	/*
+	 * BME680 Sensor
+	 */
+	epic_bme680_deinit();
+
 	return 0;
 }
diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index 5b4199b1739de26ef4a633397e0aa80dabd42c5d..dc2318359ecafaae8b78566b4ec87ecf891af44b 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -1,4 +1,5 @@
 module_sources = files(
+  'bme680.c',
   'buttons.c',
   'dispatcher.c',
   'display.c',
diff --git a/pycardium/meson.build b/pycardium/meson.build
index 40fabde700ce03eff4d117b7e5e87c024b5f35f5..f0a3798a6ab5ef5538673a98f6de9748e705f3b7 100644
--- a/pycardium/meson.build
+++ b/pycardium/meson.build
@@ -13,6 +13,7 @@ modsrc = files(
   'modules/sys_display.c',
   'modules/utime.c',
   'modules/vibra.c',
+  'modules/bme680.c'
 )
 
 #################################
diff --git a/pycardium/modules/bme680.c b/pycardium/modules/bme680.c
new file mode 100644
index 0000000000000000000000000000000000000000..c9921cd7086b44d6c70168633755aa21a02014f6
--- /dev/null
+++ b/pycardium/modules/bme680.c
@@ -0,0 +1,62 @@
+#include "py/obj.h"
+#include "py/objlist.h"
+#include "py/runtime.h"
+
+#include "epicardium.h"
+
+static mp_obj_t mp_bme680_init()
+{
+	int ret = epic_bme680_init();
+
+	if (ret < 0) {
+		mp_raise_OSError(-ret);
+	}
+
+	return 0;
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(bme680_init_obj, mp_bme680_init);
+
+static mp_obj_t mp_bme680_deinit()
+{
+	int ret = epic_bme680_deinit();
+
+	if (ret < 0) {
+		mp_raise_OSError(-ret);
+	}
+
+	return 0;
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(bme680_deinit_obj, mp_bme680_deinit);
+
+static mp_obj_t mp_bme680_get_data()
+{
+	struct bme680_sensor_data data;
+	int ret = epic_bme680_read_sensors(&data);
+
+	if (ret < 0) {
+		mp_raise_OSError(-ret);
+	}
+
+	mp_obj_t values_list[] = { mp_obj_new_float(data.temperature),
+				   mp_obj_new_float(data.humidity),
+				   mp_obj_new_float(data.pressure),
+				   mp_obj_new_float(data.gas_resistance) };
+	return mp_obj_new_tuple(4, values_list);
+}
+static MP_DEFINE_CONST_FUN_OBJ_0(bme680_get_data_obj, mp_bme680_get_data);
+
+static const mp_rom_map_elem_t bme680_module_globals_table[] = {
+	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_bme680) },
+	{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&bme680_init_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&bme680_deinit_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_get_data), MP_ROM_PTR(&bme680_get_data_obj) },
+};
+static MP_DEFINE_CONST_DICT(bme680_module_globals, bme680_module_globals_table);
+
+const mp_obj_module_t bme680_module = {
+	.base    = { &mp_type_module },
+	.globals = (mp_obj_dict_t *)&bme680_module_globals,
+};
+
+/* Register the module to make it available in Python */
+MP_REGISTER_MODULE(MP_QSTR_bme680, bme680_module, MODULE_BME680_ENABLED);
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index 6574d4369ff0ae21be5c1217fa41daa347073feb..60c5c56c9cbc385bb87fb8fe33f2f4881fd41947 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -76,6 +76,12 @@ Q(start)
 Q(get_reading)
 Q(stop)
 
+/* bme680 */
+Q(bme680)
+Q(init)
+Q(deinit)
+Q(get_data)
+
 /* file */
 Q(__del__)
 Q(__enter__)
diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h
index a1c88a7476f0b63111a4e6049aaac33f32b7fa0c..af27e146f99e46735e5f33bd013383dd47233fa7 100644
--- a/pycardium/mpconfigport.h
+++ b/pycardium/mpconfigport.h
@@ -45,6 +45,7 @@ int mp_hal_trng_read_int(void);
 #define MICROPY_PY_UERRNO                   (1)
 
 /* Modules */
+#define MODULE_BME680_ENABLED               (1)
 #define MODULE_BUTTONS_ENABLED              (1)
 #define MODULE_DISPLAY_ENABLED              (1)
 #define MODULE_GPIO_ENABLED                 (1)