diff --git a/boards/common/msb-430/Makefile b/boards/common/msb-430/Makefile
index baa55d873151f46154b83eaf906cf985093e8d3b..4695a0f76122f2071ad699558c56d5db8c4cc60a 100644
--- a/boards/common/msb-430/Makefile
+++ b/boards/common/msb-430/Makefile
@@ -1,5 +1,3 @@
 MODULE = boards_common_msb-430
 
-DIRS = drivers
-
 include $(RIOTBASE)/Makefile.base
diff --git a/boards/common/msb-430/Makefile.include b/boards/common/msb-430/Makefile.include
index 3125ba07156dde89ca3ac1024abab859dc231b86..5c054c4c66a56b51993fd9b50f34c582d588156a 100644
--- a/boards/common/msb-430/Makefile.include
+++ b/boards/common/msb-430/Makefile.include
@@ -25,6 +25,3 @@ export DEBUGGER_FLAGS = --tui --ex="target remote localhost:2000" --ex "monitor
 
 # export common msb-430 includes
 export INCLUDES += -I$(RIOTBOARD)/common/msb-430/include
-export INCLUDES += -I$(RIOTBOARD)/common/msb-430/drivers/include
-
-USEMODULE += boards_common_msb-430-drivers
diff --git a/boards/common/msb-430/drivers/Makefile b/boards/common/msb-430/drivers/Makefile
deleted file mode 100644
index ed11f0ae340a4b762ad012b7380fdc0f9e5aaecf..0000000000000000000000000000000000000000
--- a/boards/common/msb-430/drivers/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-MODULE = boards_common_msb-430-drivers
-
-include $(RIOTBOARD)/$(BOARD)/Makefile.include
-
-include $(RIOTBASE)/Makefile.base
diff --git a/boards/common/msb-430/drivers/include/sht11-board.h b/boards/common/msb-430/drivers/include/sht11-board.h
deleted file mode 100644
index a79fe22b4d9414da141707d52c31e11428a4b661..0000000000000000000000000000000000000000
--- a/boards/common/msb-430/drivers/include/sht11-board.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2013, Freie Universitaet Berlin (FUB). All rights reserved.
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-#ifndef SHT11_BOARD_H
-#define SHT11_BOARD_H
-
-/**
- * @ingroup     boards_common_msb-430
- * @{
- */
-
-/**
- * @file
- * @brief       SHT11 Device Driver Configuration For MSB-430 Platform
- *
- * @author      Freie Universität Berlin, Computer Systems & Telematics, RIOT
- *
- */
-#include <msp430x16x.h>
-#include "bitarithm.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* SCK  = P3B5
- * DATA = P3B4
- */
-
-#define SHT11_SCK_LOW   P3OUT &= ~(BIT5);     /**< serial clock line low */
-#define SHT11_SCK_HIGH  P3OUT |= BIT5;      /**< serial clock line high */
-#define SHT11_DATA      (P3IN & BIT5)      /**< read serial I/O */
-#define SHT11_DATA_LOW  P3OUT &= ~(BIT5);   /**< serial I/O line low */
-#define SHT11_DATA_HIGH P3OUT |= BIT5;      /**< serial I/O line high */
-#define SHT11_DATA_IN   P3DIR &= ~(BIT5);      /**< serial I/O as input */
-#define SHT11_DATA_OUT  P3DIR |= BIT5;      /**< serial I/O as output */
-#define SHT11_INIT      P3DIR |= BIT5;      /* FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); */
-
-#ifdef __cplusplus
-}
-#endif
-
-/** @} */
-#endif /* SHT11_BOARD_H */
diff --git a/boards/common/msba2/Makefile b/boards/common/msba2/Makefile
index a8c0997289fe79230595a9ce38d8fe672455deb8..ccf58a08443576884bb286094d185f5f49707ff5 100644
--- a/boards/common/msba2/Makefile
+++ b/boards/common/msba2/Makefile
@@ -1,5 +1,3 @@
 MODULE = boards_common_msba2
 
-DIRS = drivers
-
 include $(RIOTBASE)/Makefile.base
diff --git a/boards/common/msba2/Makefile.include b/boards/common/msba2/Makefile.include
index 5ba3b3d01cf3a541777712afb7d7229d2298ef75..00260c06232bfe698b32669e1ecf753e1c35a622 100644
--- a/boards/common/msba2/Makefile.include
+++ b/boards/common/msba2/Makefile.include
@@ -27,8 +27,5 @@ endif
 export FFLAGS = $(PORT) $(HEXFILE)
 
 INCLUDES += -I$(RIOTBOARD)/common/msba2/include
-INCLUDES += -I$(RIOTBOARD)/common/msba2/drivers/include
 
 export UNDEF += $(BINDIR)/cpu/startup.o
-
-USEMODULE += boards_common_msba2-drivers
diff --git a/boards/common/msba2/drivers/Makefile b/boards/common/msba2/drivers/Makefile
deleted file mode 100644
index 26dd1f4f5da09469500439c62212c5d5f9aa905b..0000000000000000000000000000000000000000
--- a/boards/common/msba2/drivers/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-MODULE = boards_common_msba2-drivers
-
-include $(RIOTBASE)/Makefile.base
diff --git a/boards/common/msba2/drivers/include/sht11-board.h b/boards/common/msba2/drivers/include/sht11-board.h
deleted file mode 100644
index 7ee0009965815089280778938f45db381b052104..0000000000000000000000000000000000000000
--- a/boards/common/msba2/drivers/include/sht11-board.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-#ifndef SHT11_BOARD_H
-#define SHT11_BOARD_H
-
-/**
- * @ingroup     boards_common_msba2
- * @{
- */
-
-/**
- * @file
- * @brief       LPC2387 SHT11 Device Driver
- *
- * @author      Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project
- * @version     $Revision$
- *
- * @note        $Id$
- */
-
-#include "cpu.h"
-#include "board.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*  serial clock line low */
-#define SHT11_SCK_LOW   FIO1CLR = BIT25;
-/*  serial clock line high */
-#define SHT11_SCK_HIGH  FIO1SET = BIT25;
-/*  read serial I/O */
-#define SHT11_DATA      ((FIO1PIN & BIT26) != 0)
-/*  serial I/O line low */
-#define SHT11_DATA_LOW  (FIO1CLR = BIT26);
-/*  serial I/O line high */
-#define SHT11_DATA_HIGH (FIO1SET = BIT26);
-/*  serial I/O as input */
-#define SHT11_DATA_IN   (FIO1DIR &= ~BIT26)
-/*  serial I/O as output */
-#define SHT11_DATA_OUT  (FIO1DIR |= BIT26)
-
-#define SHT11_INIT      FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17);
-
-#ifdef __cplusplus
-}
-#endif
-
-/** @} */
-#endif /* SHT11_BOARD_H */
diff --git a/boards/msb-430/Makefile.dep b/boards/msb-430/Makefile.dep
new file mode 100644
index 0000000000000000000000000000000000000000..f5124575543f30d05365553fb31a71cf64b4ab33
--- /dev/null
+++ b/boards/msb-430/Makefile.dep
@@ -0,0 +1,3 @@
+ifneq (,$(filter saul_default,$(USEMODULE)))
+  USEMODULE += sht11
+endif
diff --git a/boards/msb-430/include/board.h b/boards/msb-430/include/board.h
index a053c327f338d41cdb072833b4845f9a31e44820..7baa71f1aa0a16d481f5c8df2cc139a2c1a06732 100644
--- a/boards/msb-430/include/board.h
+++ b/boards/msb-430/include/board.h
@@ -59,6 +59,14 @@ extern "C" {
 #define MSP430_HAS_EXTERNAL_CRYSTAL 0
 /** @} */
 
+/**
+ * @name   Configure on-board SHT11 device
+ * @{
+ */
+#define SHT1X_PARAM_CLK             (GPIO_PIN(3, 5))
+#define SHT1X_PARAM_DATA            (GPIO_PIN(3, 4))
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/msb-430h/Makefile.dep b/boards/msb-430h/Makefile.dep
new file mode 100644
index 0000000000000000000000000000000000000000..f5124575543f30d05365553fb31a71cf64b4ab33
--- /dev/null
+++ b/boards/msb-430h/Makefile.dep
@@ -0,0 +1,3 @@
+ifneq (,$(filter saul_default,$(USEMODULE)))
+  USEMODULE += sht11
+endif
diff --git a/boards/msb-430h/include/board.h b/boards/msb-430h/include/board.h
index 8fc284faa1f3e9e1463c13ccc82d6f55edd99058..ae744f1b5f0432a32c9a636daea553f06a5ba5d3 100644
--- a/boards/msb-430h/include/board.h
+++ b/boards/msb-430h/include/board.h
@@ -47,6 +47,14 @@ extern "C" {
 #define MSP430_HAS_EXTERNAL_CRYSTAL 1
 /** @} */
 
+/**
+ * @name   Configure on-board SHT11 device
+ * @{
+ */
+#define SHT1X_PARAM_CLK             (GPIO_PIN(3, 5))
+#define SHT1X_PARAM_DATA            (GPIO_PIN(3, 4))
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/boards/msba2/Makefile.dep b/boards/msba2/Makefile.dep
index e5d94f2d25850c062976f10d5a38ff3fca618243..d7230f86c2db4c22efab874deb9b8f70a1c0c7f2 100644
--- a/boards/msba2/Makefile.dep
+++ b/boards/msba2/Makefile.dep
@@ -3,3 +3,7 @@ include $(RIOTBOARD)/common/msba2/Makefile.dep
 ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
   USEMODULE += cc110x
 endif
+
+ifneq (,$(filter saul_default,$(USEMODULE)))
+  USEMODULE += sht11
+endif
diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep
index 48f58ce29532725f7abffe93aaa0447fdcfbb490..776b16540929f08b059d5b0849323ec3bc723ab7 100644
--- a/drivers/Makefile.dep
+++ b/drivers/Makefile.dep
@@ -307,7 +307,9 @@ ifneq (,$(filter servo,$(USEMODULE)))
   FEATURES_REQUIRED += periph_pwm
 endif
 
-ifneq (,$(filter sht11,$(USEMODULE)))
+ifneq (,$(filter sht1%,$(USEMODULE)))
+  USEMODULE += sht1x
+  FEATURES_REQUIRED += periph_gpio
   USEMODULE += xtimer
 endif
 
diff --git a/drivers/Makefile.include b/drivers/Makefile.include
index 7bf99640856ac668b4eafdf5ad4883ab61e1f0a1..e37c2b67522e8cc622c548341242141e8bf1861e 100644
--- a/drivers/Makefile.include
+++ b/drivers/Makefile.include
@@ -50,6 +50,10 @@ ifneq (,$(filter dht,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dht/include
 endif
 
+ifneq (,$(filter sht1x,$(USEMODULE)))
+  USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht1x/include
+endif
+
 ifneq (,$(filter ds1307,$(USEMODULE)))
   USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds1307/include
 endif
diff --git a/drivers/include/sht11.h b/drivers/include/sht11.h
deleted file mode 100644
index 2378ca8c1b83245ec00a8af111af5bae7845c506..0000000000000000000000000000000000000000
--- a/drivers/include/sht11.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-/**
- * @defgroup    drivers_sht11 SHT11 Humidity and Temperature Sensor
- * @ingroup     drivers_sensors
- * @brief       Driver for Sensirion SHT11 Humidity and Temperature Sensor
- * @{
- *
- * @file
- * @brief       SHT11 Device Driver
- *
- * @author      Freie Universität Berlin, Computer Systems & Telematics
- */
-
-#ifndef SHT11_H
-#define SHT11_H
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SHT11_NO_ACK        (0)     /**< don't ack read in `read_byte` */
-#define SHT11_ACK           (1)     /**< do acknowledge read in `read_byte` */
-/* adr command  r/w */
-#define SHT11_STATUS_REG_W  (0x06)  /**< will write to status register */
-#define SHT11_STATUS_REG_R  (0x07)  /**< will read from status register */
-#define SHT11_MEASURE_TEMP  (0x03)  /**< tell sensor to measure temperature */
-#define SHT11_MEASURE_HUMI  (0x05)  /**< tell sensor to measure humidity */
-#define SHT11_RESET         (0x1E)  /**< reset the sensor */
-
-/** time to wait after toggling the data line */
-#define SHT11_DATA_WAIT     (1)
-/** time to wait after toggling the clock line */
-#define SHT11_CLK_WAIT      (1)
-
-/** set measurement timeout to 1 second */
-#define SHT11_MEASURE_TIMEOUT   (1000)
-
-/**
- * @brief   sht11 measureable data
- */
-typedef struct {
-    float   temperature;    /**< temperature value */
-    float   relhum;         /**< linear relative humidity */
-    float   relhum_temp;    /**< temperature compensated relative humidity */
-} sht11_val_t;
-
-/**
- * @brief   SHT11 modes that can be measured
- */
-typedef enum {
-    TEMPERATURE = 1,
-    HUMIDITY = 2
-} sht11_mode_t;
-
-/**
- * @brief   Initialize SHT11 ports
- */
-void sht11_init(void);
-
-/**
- * @brief   Read sensor
- *
- * @param value The struct to be filled with measured values
- * @param mode  Specifies type of data to be read
- *
- * @return  1 on success, 0 otherwise
- *
- * Example:
- * \code sht11_val sht11;
- * sht11_read_sensor(&sht11, HUMIDITY|TEMPERATURE);
- * printf("%-6.2f °C %5.2f %% %5.2f %%\n", sht11.temperature, sht11.relhum, sht11.relhum_temp); \endcode
- */
-uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode);
-
-/**
- * @brief   Write status register
- *
- * @param   p_value The value to write
- *
- * @return  1 on success, 0 otherwise
- */
-uint8_t sht11_write_status(uint8_t *p_value);
-
-/**
- * @brief   Read status register with checksum
- *
- * @param   p_value The read value
- * @param   p_checksum The received checksum
- *
- * return   1 on success, 0 otherwise
- */
-uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SHT11_H */
-/** @} */
diff --git a/drivers/include/sht1x.h b/drivers/include/sht1x.h
new file mode 100644
index 0000000000000000000000000000000000000000..b8c7bd87197323e29e0f5728f1d48490e744e6e2
--- /dev/null
+++ b/drivers/include/sht1x.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2009 Freie Universitaet Berlin (FUB)
+ *           2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    drivers_sht1x SHT10/SHT11/SHT15 Humidity and Temperature Sensor
+ * @ingroup     drivers_sensors
+ * @brief       Driver for Sensirion SHT10/SHT11/SHT15 Humidity and Temperature
+                Sensor
+ * @{
+ *
+ * @file
+ * @brief       SHT10/SHT11/SHT15 Device Driver
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ */
+
+#ifndef SHT1X_H
+#define SHT1X_H
+
+#include <stdint.h>
+#include <periph/gpio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Possible configuration (=status byte) values of the SHT10/11/15
+ *
+ * These values can be or'ed together to get the configuration.
+ */
+typedef enum {
+    /** Use 8/12 bit resolution instead of 12/14 bit for temp/hum */
+    SHT1X_CONF_LOW_RESOLUTION   = 0x01,
+    /** Don't upload calibration data to register to safe 10 millisec */
+    SHT1X_CONF_SKIP_CALIBRATION = 0x02,
+    /** Waste 8mA at 5V to increase the sensor temperature up to 10°C */
+    SHT1X_CONF_ENABLE_HEATER    = 0x04,
+    /** Skip the CRC check (and reading the CRC byte) to safe time */
+    SHT1X_CONF_SKIP_CRC         = 0x08,
+} sht1x_conf_t;
+
+/**
+ * @brief Possible values for Vdd (measured temperature depends on it)
+ */
+typedef enum {
+    SHT1X_VDD_5_0V = 0,
+    SHT1X_VDD_4_0V = 1,
+    SHT1X_VDD_3_5V = 2,
+    SHT1X_VDD_3_0V = 3,
+    SHT1X_VDD_2_5V = 4,
+} sht1x_vdd_t;
+
+/**
+ * @brief SHT10/11/15 temperature humidity sensor
+ */
+typedef struct {
+    gpio_t  clk;      /**< GPIO connected to the clock pin of the SHT1X */
+    gpio_t  data;     /**< GPIO connected to the data pin of the SHT1X */
+    int16_t temp_off; /**< Offset to add to the measured temperature */
+    int16_t hum_off;  /**< Offset to add to the measured humidity */
+    uint8_t conf;     /**< Status byte (containing configuration) of the SHT1X */
+    uint8_t vdd;      /**< Supply voltage of the SHT1X (as sht1x_vdd_t) */
+} sht1x_dev_t;
+
+/**
+ * @brief Parameters required to set up the SHT10/11/15 device driver
+ */
+typedef struct {
+    gpio_t      clk;  /**< GPIO connected to the clock pin of the SHT1X */
+    gpio_t      data; /**< GPIO connected to the data pin of the SHT1X */
+    sht1x_vdd_t vdd;  /**< The supply voltage of the SHT1X */
+} sht1x_params_t;
+
+/**
+ * @brief             Initialize the SHT10/11/15 sensor
+ *
+ * @param  dev        SHT1X sensor to initialize
+ * @param  params     Information on how the SHT1X is connected to the board
+ *
+ * @retval  0         Success
+ * @retval -EIO       IO failure (`gpio_init()` failed)
+ * @retval -EPROTO    Sensor did not acknowledge reset command
+ */
+int sht1x_init(sht1x_dev_t *dev, const sht1x_params_t *params);
+
+/**
+ * @brief             Calculate the temperature from the raw input
+ * @note              This internal function is exposed for unit tests
+ *
+ * @param dev         Device from which the raw value was received
+ * @param raw         The raw (unprocessed) temperature value
+ *
+ * @return            The correct temperature in E-02 °C
+ * @retval INT16_MIN  Passed `NULL` for parameter `dev` or `dev->vdd`
+ */
+int16_t sht1x_temperature(const sht1x_dev_t *dev, uint16_t raw);
+
+/**
+ * @brief             Calculate the relative humidity from the raw input
+ * @note              This internal function is exposed for unit tests
+ *
+ * @param dev         Device from which the raw value was received
+ * @param raw         The raw (unprocessed) temperature value
+ * @param temp        The temperature at which the humidity was measure in
+ *                    E-02 °C
+ *
+ * @return            The correct temperature in E-02 %
+ * @retval -1         Passed `NULL` for parameter `dev`
+ */
+int16_t sht1x_humidity(const sht1x_dev_t *dev, uint16_t raw, int16_t temp);
+
+/**
+ * @brief             Read the current temperature
+ *
+ * @param dev         SHT1X sensor to read
+ * @param temp        Store the measured temperature in E-02 °C here
+ * @param hum         Store the measured relative humidity in E-02 % here
+ *
+ * @retval  0         Success
+ * @retval -EIO       IO failure (`gpio_init()` failed)
+ * @retval -EBADMSG   CRC-8 checksum didn't match (--> Retry)
+ * @retval -EINVAL    Passed `NULL` for dev or for both `temp` and `hum`
+ * @retval -EBADMSG   CRC checksum didn't match
+ * @retval -ECANCELED Measurement timed out
+ * @retval -EPROTO    Sensor did not acknowledge command
+ *
+ * For either `temp` or `hum` `NULL` can be passed, if only one value is of
+ * interest. Passing `NULL` for `hum` speeds up the communication, but
+ * passing `NULL` for `temp` does not. The temperature value is required to
+ * calculate the relative humidity from the raw input. So the temperature is
+ * measured in any case, it is just not returned if `temp` is `NULL`.
+ */
+int sht1x_read(const sht1x_dev_t *dev, int16_t *temp, int16_t *hum);
+
+/**
+ * @brief             Apply the given configuration (= status byte) to
+ *
+ * @param dev         SHT1X device to configure
+ * @param conf        Configuration to apply
+ *
+ * @retval  0         Configuration applied
+ * @retval -EINVAL    Called with `dev == NULL`
+ * @retval -EIO       I/O error (`gpio_init()` failed)
+ * @retval -EPROTO    Sensor did not acknowledge command
+ * @retval -ECANCELED Sensor did not apply configuration
+ * @retval -EBADMSG   CRC checksum error while verifying uploaded configuration
+ */
+int sht1x_configure(sht1x_dev_t *dev, sht1x_conf_t conf);
+
+/**
+ * @brief             Read the status byte of an SHT1X sensor
+ *
+ * @param dev         SHT1X device to receive the status from
+ * @param status      Store the received status byte here
+ *
+ * @retval  0         Configuration applied
+ * @retval -EINVAL    Called with `dev == NULL`
+ * @retval -EIO       I/O error (`gpio_init()` failed)
+ * @retval -EPROTO    Sensor did not acknowledge command
+ * @retval -EBADMSG   CRC checksum didn't match
+ */
+int sht1x_read_status(sht1x_dev_t *dev, uint8_t *status);
+
+/**
+ * @brief             Reset the sensor's configuration to default values
+ *
+ * @param dev         SHT1X device to reset
+ *
+ * @retval  0         Reset successful
+ * @retval -EINVAL    Called with `dev == NULL`
+ * @retval -EIO       I/O error (`gpio_init()` failed)
+ * @retval -EPROTO    Sensor did not acknowledge reset command
+ */
+int sht1x_reset(sht1x_dev_t *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SHT1X_H */
+/** @} */
diff --git a/drivers/sht11/sht11.c b/drivers/sht11/sht11.c
deleted file mode 100644
index e92b15013b7f6b605d4170dafe7f7b9f9f89f0d7..0000000000000000000000000000000000000000
--- a/drivers/sht11/sht11.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-/**
- * @ingroup     drivers_sht11
- * @brief       Driver for the Sensirion SHT11 humidity and temperature sensor
- * @{
- *
- * @file
- * @brief       SHT11 Device Driver
- *
- * @version     $Revision: 2396 $
- *
- * @note        $Id: sht11.c 2396 2010-07-06 15:12:35Z ziegert $
- * @}
- */
-
-#include <stdio.h>
-#include <stdint.h>
-
-#include "xtimer.h"
-#include "mutex.h"
-#include "sht11.h"
-#include "sht11-board.h"
-#include "bitarithm.h"
-
-float sht11_temperature_offset;
-
-/**
- * @brief   Perform measurement
- *
- * @param   p_value Measured value (14 or 12 bit -> 2 bytes)
- * @param   p_checksum Checksum of measurement
- * @param   mode The requestested measurement mode: temperature or humidity
- *
- * @return  1 on success, 0 otherwise
- */
-static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode);
-
-/**
- * @brief   Write one byte
- *
- * @param   value The value to write
- *
- * @return  1 for acknowledged write, 0 otherwise
- */
-static uint8_t write_byte(uint8_t value);
-
-/**
- * @brief   Read ony byte
- *
- * @param   ack Set if the data read should be acknowledged
- *
- * @return  The read byte
- */
-static uint8_t read_byte(uint8_t ack);
-
-/**
- * @brief   Communication reset
- */
-static void connection_reset(void);
-
-/**
- * @brief   Send start of transmision sequence
- */
-static void transmission_start(void);
-
-/**
- * @brief   Toggle the clock line
- */
-static inline void clk_signal(void);
-
-/* mutex for exclusive measurement operation */
-mutex_t sht11_mutex = MUTEX_INIT;
-
-/*---------------------------------------------------------------------------*/
-static inline void clk_signal(void)
-{
-    SHT11_SCK_HIGH;
-    xtimer_usleep(SHT11_CLK_WAIT);
-    SHT11_SCK_LOW;
-    xtimer_usleep(SHT11_CLK_WAIT);
-}
-
-/*---------------------------------------------------------------------------*/
-static uint8_t write_byte(uint8_t value)
-{
-    uint8_t i;
-    uint8_t ack;
-
-    SHT11_DATA_OUT;
-
-    /* send value bit by bit to sht11 */
-    for (i = 0; i < 8; i++) {
-        if (value & BIT7) {
-            SHT11_DATA_HIGH;
-            xtimer_usleep(SHT11_DATA_WAIT);
-        }
-        else {
-            SHT11_DATA_LOW;
-            xtimer_usleep(SHT11_DATA_WAIT);
-        }
-
-        /* trigger clock signal */
-        clk_signal();
-
-        /* shift value to write next bit */
-        value = value << 1;
-    }
-
-    /* wait for ack */
-    SHT11_DATA_IN;
-    xtimer_usleep(SHT11_CLK_WAIT);
-    ack = SHT11_DATA;
-
-    clk_signal();
-
-    return ack;
-}
-/*---------------------------------------------------------------------------*/
-static uint8_t read_byte(uint8_t ack)
-{
-    uint8_t i;
-    uint8_t value = 0;
-
-    SHT11_DATA_IN;
-    xtimer_usleep(SHT11_DATA_WAIT);
-
-    /* read value bit by bit */
-    for (i = 0; i < 8; i++) {
-        value = value << 1;
-        SHT11_SCK_HIGH;
-        xtimer_usleep(SHT11_CLK_WAIT);
-
-        if (SHT11_DATA) {
-            /* increase data by one when DATA is high */
-            value++;
-        }
-
-        SHT11_SCK_LOW;
-        xtimer_usleep(SHT11_CLK_WAIT);
-    }
-
-    /* send ack if necessary */
-    SHT11_DATA_OUT;
-
-    if (ack) {
-        SHT11_DATA_LOW;
-        xtimer_usleep(SHT11_DATA_WAIT);
-    }
-    else {
-        SHT11_DATA_HIGH;
-        xtimer_usleep(SHT11_DATA_WAIT);
-    }
-
-    clk_signal();
-
-    /* release data line */
-    SHT11_DATA_IN;
-
-    return value;
-}
-/*---------------------------------------------------------------------------*/
-static void transmission_start(void)
-{
-    /*       _____         ________
-       DATA:      |_______|
-                 ___     ___
-       SCK : ___|   |___|   |______
-    */
-    SHT11_DATA_OUT;
-
-    /* set initial state */
-    SHT11_DATA_HIGH;
-    xtimer_usleep(SHT11_DATA_WAIT);
-    SHT11_SCK_LOW;
-    xtimer_usleep(SHT11_CLK_WAIT);
-
-    SHT11_SCK_HIGH;
-    xtimer_usleep(SHT11_CLK_WAIT);
-
-    SHT11_DATA_LOW;
-    xtimer_usleep(SHT11_DATA_WAIT);
-
-    SHT11_SCK_LOW;
-    xtimer_usleep(SHT11_CLK_WAIT);
-
-    SHT11_SCK_HIGH;
-    xtimer_usleep(SHT11_CLK_WAIT);
-
-    SHT11_DATA_HIGH;
-    xtimer_usleep(SHT11_DATA_WAIT);
-
-    SHT11_SCK_LOW;
-    xtimer_usleep(SHT11_CLK_WAIT);
-}
-/*---------------------------------------------------------------------------*/
-static void connection_reset(void)
-{
-    /*       _____________________________________________________         ____
-       DATA:                                                      |_______|
-                _    _    _    _    _    _    _    _    _        ___     ___
-       SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |__
-    */
-    uint8_t i;
-    SHT11_DATA_HIGH;
-    xtimer_usleep(SHT11_DATA_WAIT);
-    SHT11_SCK_LOW;
-    xtimer_usleep(SHT11_CLK_WAIT);
-
-    for (i = 0; i < 9; i++) {
-        clk_signal();
-    }
-
-    transmission_start();
-}
-/*---------------------------------------------------------------------------*/
-static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
-{
-    uint8_t error = 0;
-    uint8_t ack = 1;
-    uint16_t i;
-
-    transmission_start();
-    error = write_byte(mode);
-
-    xtimer_usleep(1000);
-
-    /* wait untile sensor has finished measurement or timeout */
-    for (i = 0; (i < SHT11_MEASURE_TIMEOUT) && (!error); i++) {
-        ack = SHT11_DATA;
-
-        if (!ack) {
-            break;
-        }
-
-        xtimer_usleep(1000);
-    }
-
-    error += ack;
-
-    /* read MSB */
-    *(p_value + 1) = read_byte(SHT11_ACK);
-    /* read LSB */
-    *(p_value) = read_byte(SHT11_ACK);
-    /* read checksum */
-    *p_checksum = read_byte(SHT11_NO_ACK);
-
-    return (!error);
-}
-/*---------------------------------------------------------------------------*/
-void sht11_init(void)
-{
-    sht11_temperature_offset = 0;
-    SHT11_INIT;
-    xtimer_usleep(11 * 1000);
-}
-/*---------------------------------------------------------------------------*/
-uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum)
-{
-    uint8_t error = 0;
-
-    transmission_start();
-    error |= write_byte(SHT11_STATUS_REG_R);
-    *p_value = read_byte(SHT11_ACK);
-    *p_checksum = read_byte(SHT11_NO_ACK);
-    return (!error);
-}
-/*---------------------------------------------------------------------------*/
-uint8_t sht11_write_status(uint8_t *p_value)
-{
-    uint8_t error = 0;
-
-    transmission_start();
-    error += write_byte(SHT11_STATUS_REG_W);
-    error += write_byte(*p_value);
-    return (!error);
-}
-/*---------------------------------------------------------------------------*/
-uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode)
-{
-    uint8_t error = 0;
-    uint8_t checksum;
-    uint16_t humi_int, temp_int;
-
-    /* Temperature arithmetic where S0(T) is read value
-     * T = D1 + D2 * S0(T) */
-    const float D1 = -39.6;
-    const float D2 = 0.01;
-
-    /* Arithmetic for linear humdity where S0(RH) is read value
-     * HL = C1 + C2 * S0(RH) + C3 * SO(RH)^2 */
-    const float C1 = -4.0;
-    const float C2 = +0.0405;
-    const float C3 = -0.0000028;
-
-    /* Arithmetic for temperature compesated relative humdity
-     * HT = (T-25) * ( T1 + T2 * SO(RH) ) + HL */
-    const float T1 = +0.01;
-    const float T2 = +0.00008;
-
-    /* check for valid buffer */
-    if (value == NULL) {
-        return 0;
-    }
-
-    value->temperature = 0;
-    value->relhum = 0;
-    value->relhum_temp = 0;
-
-    mutex_lock(&sht11_mutex);
-    connection_reset();
-
-    /* measure humidity */
-    if (mode & HUMIDITY) {
-        error += (!measure((uint8_t *) &humi_int, &checksum, SHT11_MEASURE_HUMI));
-    }
-
-    /* measure temperature */
-    if (mode & TEMPERATURE) {
-        error += (!measure((uint8_t *) &temp_int, &checksum, SHT11_MEASURE_TEMP));
-    }
-
-    /* break on error */
-    if (error != 0) {
-        connection_reset();
-        mutex_unlock(&sht11_mutex);
-        return 0;
-    }
-
-    if (mode & TEMPERATURE) {
-        value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset;
-    }
-
-    if (mode & HUMIDITY) {
-        value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
-
-        if (mode & TEMPERATURE) {
-            value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum;
-        }
-    }
-
-    mutex_unlock(&sht11_mutex);
-    return 1;
-}
diff --git a/drivers/sht11/Makefile b/drivers/sht1x/Makefile
similarity index 100%
rename from drivers/sht11/Makefile
rename to drivers/sht1x/Makefile
diff --git a/drivers/sht1x/include/sht1x_defines.h b/drivers/sht1x/include/sht1x_defines.h
new file mode 100644
index 0000000000000000000000000000000000000000..0327387ab08d78cedf0c80f87eb46ea52b5c8514
--- /dev/null
+++ b/drivers/sht1x/include/sht1x_defines.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2009 Freie Universitaet Berlin (FUB)
+ *           2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_sht1x
+ * @{
+ *
+ * @file
+ * @brief       Internal defines required by the SHT10/SHT11/SHT15 driver
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ */
+
+#ifndef SHT1X_DEFINES_H
+#define SHT1X_DEFINES_H
+
+#include <stdint.h>
+#include <periph/gpio.h>
+#include <mutex.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name Possible values to pass as `ack` parameter to `write_byte`
+ * @see write_byte
+ * @{
+ */
+#define SHT1X_NO_ACK           (1)      /**< don't ack read in `read_byte` */
+#define SHT1X_ACK              (0)      /**< do acknowledge read in `read_byte` */
+/** @} */
+
+/**
+ * @name Commands that can be sent to the SHT1X driver
+ * @{
+ */
+#define SHT1X_STATUS_REG_W     (0x06)   /**< will write to status register */
+#define SHT1X_STATUS_REG_R     (0x07)   /**< will read from status register */
+#define SHT1X_MEASURE_TEMP     (0x03)   /**< tell sensor to measure temperature */
+#define SHT1X_MEASURE_HUM      (0x05)   /**< tell sensor to measure humidity */
+#define SHT1X_RESET            (0x1E)   /**< reset the sensor */
+/** @} */
+
+/**
+ * @name Timing parameters for the SHT10/SHT1X/SHT15
+ * @{
+ */
+#define SHT1X_HALF_CLOCK        (1)     /**< Half clock length in µsec */
+#define SHT1X_MEASURE_TIMEOUT   (1000)  /**< Timeout for the SHT1x to complete
+                                             the measurement (in millisec) */
+#define SHT1X_RESET_WAIT        (11000) /**< Wait 11ms after soft reset */
+/** @} */
+
+#define SHT1X_CONF_MASK         (0x07)  /**< Bitmask to get writable bits of the
+                                             status byte */
+#define SHT1X_SAUL_RETRIES      (3)     /**< How often reading the sensor should
+                                             be retried in case of communication
+                                             failures */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SHT1X_DEFINES_H */
+/** @} */
diff --git a/drivers/sht1x/include/sht1x_params.h b/drivers/sht1x/include/sht1x_params.h
new file mode 100644
index 0000000000000000000000000000000000000000..02b94c784de41ed8e5b0eaaedf1caed0debb7668
--- /dev/null
+++ b/drivers/sht1x/include/sht1x_params.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_sht1x
+ *
+ * @{
+ * @file
+ * @brief       Default configuration for SHT10/SHT11/SHT15 devices
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ */
+
+#ifndef SHT1X_PARAMS_H
+#define SHT1X_PARAMS_H
+
+#include "board.h"
+#include "sht1x.h"
+#include "saul_reg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name    Set default configuration parameters for the SHT1X devices
+ * @{
+ */
+#ifndef SHT1X_PARAM_CLK
+#define SHT1X_PARAM_CLK               (GPIO_PIN(1, 25))
+#endif
+#ifndef SHT1X_PARAM_DATA
+#define SHT1X_PARAM_DATA              (GPIO_PIN(1, 26))
+#endif
+#ifndef SHT1X_PARAM_VDD
+#define SHT1X_PARAM_VDD               (SHT1X_VDD_3_5V)
+#endif
+#ifndef SHT1X_PARAMS
+#define SHT1X_PARAMS                  { .clk = SHT1X_PARAM_CLK,  \
+                                        .data = SHT1X_PARAM_DATA, \
+                                        .vdd = SHT1X_PARAM_VDD }
+#endif
+/**@}*/
+
+/**
+ * @name    Set default SAUL info text depending on used pseudo module
+ * @{
+ */
+#ifndef SHT1X_SAULINFO
+#ifdef MODULE_SHT15
+#define SHT1X_SAULINFO                { .name = "SHT15 temperature" }, \
+                                      { .name = "SHT15 humidity" }
+#else
+#ifdef MODULE_SHT10
+#define SHT1X_SAULINFO                { .name = "SHT10 temperature" }, \
+                                      { .name = "SHT10 humidity" }
+#else
+/* SHT11 is the most commonly used, so use that as default */
+#define SHT1X_SAULINFO                { .name = "SHT11 temperature" }, \
+                                      { .name = "SHT11 humidity" }
+#endif /* MODULE_SHT10 */
+#endif /* MODULE_SHT15 */
+#endif /* SHT1X_SAULINFO */
+
+/**@}*/
+
+/**
+ * @brief   Configure SHT1X devices
+ */
+static const sht1x_params_t sht1x_params[] =
+{
+    SHT1X_PARAMS
+};
+
+/**
+ * @brief   Allocate and configure entries to the SAUL registry
+ */
+static const saul_reg_info_t sht1x_saul_info[] =
+{
+    SHT1X_SAULINFO
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SHT1X_PARAMS_H */
+/** @} */
diff --git a/drivers/sht1x/sht1x.c b/drivers/sht1x/sht1x.c
new file mode 100644
index 0000000000000000000000000000000000000000..f2a55cc0139e168001c18a47e374fca56ad69558
--- /dev/null
+++ b/drivers/sht1x/sht1x.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright 2009 Freie Universitaet Berlin (FUB)
+ *           2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_sht1x
+ * @brief       Driver for the Sensirion SHT10/SHT11/SHT15 humidity and
+ *              temperature sensor
+ * @{
+ *
+ * @file
+ * @brief       SHT10/SHT11/SHT15 Device Driver
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ *
+ * @}
+ */
+#include <errno.h>
+#include <stdint.h>
+
+#include "xtimer.h"
+#include "sht1x.h"
+#include "sht1x_defines.h"
+#include "bitarithm.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+/**
+ * @brief             Perform measurement
+ *
+ * @param dev         SHT1X device to use
+ * @param value       Measured value
+ * @param mode        The requested measurement mode: temperature or humidity
+ *
+ * @retval  0         Success
+ * @retval -EIO       I/O failure (`gpio_init()` failed)
+ * @retval -EBADMSG   CRC-8 checksum didn't match
+ * @retval -EPROTO    SHT1x did not acknowledge command
+ * @retval -ECANCELED Measurement timed out
+ */
+static int measure(const sht1x_dev_t *dev, uint16_t *value, uint8_t mode);
+
+/**
+ * @brief             Write one byte
+ *
+ * @param  dev        SHT1X device to send the byte to
+ * @param  value      The value to write
+ *
+ * @retval  1         Write was acknowledged
+ * @retval  0         Write was *NOT* acknowledged (communication failure)
+ * @retval -EIO       I/O failure (`gpio_init()` failed)
+ */
+static int write_byte(const sht1x_dev_t *dev, uint8_t value);
+
+/**
+ * @brief             Read one byte
+ *
+ * @param  dev        SHT1X device to receive the byte from
+ * @param  dest       Store the received byte here
+ * @param  ack        `SHT1X_ACK` to acknowledge byte, `SHT1X_NO_ACK` otherwise
+ *
+ * @retval  0         Success
+ * @retval -EIO       I/O failure (`gpio_init()` failed)
+ */
+static int read_byte(const sht1x_dev_t *dev, uint8_t *dest, int ack);
+
+/**
+ * @brief             Communication reset
+ *
+ * @param  dev        SHT1X device to reset the connection to
+ *
+ * @retval  0         Success
+ * @retval -EIO       I/O failure (`gpio_init()` failed)
+ */
+static int connection_reset(const sht1x_dev_t *dev);
+
+/**
+ * @brief             Send start of transmission sequence
+ *
+ * @param  dev        SHT1X device to send the transmission start sequence to
+ *
+ * @retval  0         Success
+ * @retval -EIO       I/O failure (`gpio_init()` failed)
+ */
+static int transmission_start(const sht1x_dev_t *dev);
+
+/**
+ * @brief             Toggle the clock line
+ *
+ * @param  dev        SHT1X device to send one clock signal to
+ */
+static inline void clk_signal(const sht1x_dev_t *dev);
+
+/**
+ * @brief             Calculate the initial value of the CRC-8 checksum
+ *
+ * @param status      The current sensor status
+ *
+ * @return            The initial value of the CRC-8 checksum
+ */
+static inline uint8_t crc_initial_value(uint8_t status);
+
+/**
+ * @brief             Reverse the order of bits in a byte (needed for CRC)
+ *
+ * @param value       The byte to reverse the bits of
+ *
+ * @return            The reversed input
+ */
+static inline uint8_t reverse_byte(uint8_t value);
+
+/**
+ * @brief             Look up table required for CRC-8 calculation
+ *
+ * Values taken from the Application Note PDF of Sensirion (December 2011)
+ */
+static const uint8_t crc_lookup_table[] = {
+    0x00, 0x31, 0x62, 0x53,  0xc4, 0xf5, 0xa6, 0x97,
+    0xb9, 0x88, 0xdb, 0xea,  0x7d, 0x4c, 0x1f, 0x2e,
+    0x43, 0x72, 0x21, 0x10,  0x87, 0xb6, 0xe5, 0xd4,
+    0xfa, 0xcb, 0x98, 0xa9,  0x3e, 0x0f, 0x5c, 0x6d,
+    0x86, 0xb7, 0xe4, 0xd5,  0x42, 0x73, 0x20, 0x11,
+    0x3f, 0x0e, 0x5d, 0x6c,  0xfb, 0xca, 0x99, 0xa8,
+    0xc5, 0xf4, 0xa7, 0x96,  0x01, 0x30, 0x63, 0x52,
+    0x7c, 0x4d, 0x1e, 0x2f,  0xb8, 0x89, 0xda, 0xeb,
+    0x3d, 0x0c, 0x5f, 0x6e,  0xf9, 0xc8, 0x9b, 0xaa,
+    0x84, 0xb5, 0xe6, 0xd7,  0x40, 0x71, 0x22, 0x13,
+    0x7e, 0x4f, 0x1c, 0x2d,  0xba, 0x8b, 0xd8, 0xe9,
+    0xc7, 0xf6, 0xa5, 0x94,  0x03, 0x32, 0x61, 0x50,
+    0xbb, 0x8a, 0xd9, 0xe8,  0x7f, 0x4e, 0x1d, 0x2c,
+    0x02, 0x33, 0x60, 0x51,  0xc6, 0xf7, 0xa4, 0x95,
+    0xf8, 0xc9, 0x9a, 0xab,  0x3c, 0x0d, 0x5e, 0x6f,
+    0x41, 0x70, 0x23, 0x12,  0x85, 0xb4, 0xe7, 0xd6,
+    0x7a, 0x4b, 0x18, 0x29,  0xbe, 0x8f, 0xdc, 0xed,
+    0xc3, 0xf2, 0xa1, 0x90,  0x07, 0x36, 0x65, 0x54,
+    0x39, 0x08, 0x5b, 0x6a,  0xfd, 0xcc, 0x9f, 0xae,
+    0x80, 0xb1, 0xe2, 0xd3,  0x44, 0x75, 0x26, 0x17,
+    0xfc, 0xcd, 0x9e, 0xaf,  0x38, 0x09, 0x5a, 0x6b,
+    0x45, 0x74, 0x27, 0x16,  0x81, 0xb0, 0xe3, 0xd2,
+    0xbf, 0x8e, 0xdd, 0xec,  0x7b, 0x4a, 0x19, 0x28,
+    0x06, 0x37, 0x64, 0x55,  0xc2, 0xf3, 0xa0, 0x91,
+    0x47, 0x76, 0x25, 0x14,  0x83, 0xb2, 0xe1, 0xd0,
+    0xfe, 0xcf, 0x9c, 0xad,  0x3a, 0x0b, 0x58, 0x69,
+    0x04, 0x35, 0x66, 0x57,  0xc0, 0xf1, 0xa2, 0x93,
+    0xbd, 0x8c, 0xdf, 0xee,  0x79, 0x48, 0x1b, 0x2a,
+    0xc1, 0xf0, 0xa3, 0x92,  0x05, 0x34, 0x67, 0x56,
+    0x78, 0x49, 0x1a, 0x2b,  0xbc, 0x8d, 0xde, 0xef,
+    0x82, 0xb3, 0xe0, 0xd1,  0x46, 0x77, 0x24, 0x15,
+    0x3b, 0x0a, 0x59, 0x68,  0xff, 0xce, 0x9d, 0xac,
+};
+
+/** @brief Lookuptable for d1 parameter depending on supply voltage */
+static const int16_t sht1x_d1[] = { -4010, -3980, -3970, -3960, -3940 };
+
+/*---------------------------------------------------------------------------*/
+static inline void clk_signal(const sht1x_dev_t *dev)
+{
+    gpio_set(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+    gpio_clear(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+}
+
+/*---------------------------------------------------------------------------*/
+static int write_byte(const sht1x_dev_t *dev, uint8_t value)
+{
+    int ack;
+
+    if (gpio_init(dev->data, GPIO_OUT) == -1) {
+        return -EIO;
+    }
+
+    /* send value bit by bit to sht1x */
+    for (int i = 0; i < 8; i++) {
+        if (value & BIT7) {
+            gpio_set(dev->data);
+        }
+        else {
+            gpio_clear(dev->data);
+        }
+        xtimer_usleep(SHT1X_HALF_CLOCK);
+
+        /* trigger clock signal */
+        clk_signal(dev);
+
+        /* shift value to write next bit */
+        value <<= 1;
+    }
+
+    /* wait for ack */
+    if (gpio_init(dev->data, GPIO_IN) == -1) {
+        return -EIO;
+    }
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+    ack = gpio_read(dev->data);
+
+    clk_signal(dev);
+
+    return ack;
+}
+
+/*---------------------------------------------------------------------------*/
+static int read_byte(const sht1x_dev_t *dev, uint8_t *dest, int ack)
+{
+    uint8_t value = 0;
+
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    /* read value bit by bit */
+    for (int i = 0; i < 8; i++) {
+        value <<= 1;
+        gpio_set(dev->clk);
+        xtimer_usleep(SHT1X_HALF_CLOCK);
+
+        if (gpio_read(dev->data)) {
+            /* set bit when DATA is high */
+            value |= 0x01;
+        }
+
+        gpio_clear(dev->clk);
+        xtimer_usleep(SHT1X_HALF_CLOCK);
+    }
+
+    /* send ack if necessary */
+    if (gpio_init(dev->data, GPIO_OUT) == -1) {
+        return -EIO;
+    }
+
+    gpio_write(dev->data, ack);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    clk_signal(dev);
+
+    /* release data line */
+    if (gpio_init(dev->data, GPIO_IN) == -1) {
+        return -EIO;
+    }
+
+    *dest = value;
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static int transmission_start(const sht1x_dev_t *dev)
+{
+    /*       _____         ________
+       DATA:      |_______|
+                 ___     ___
+       SCK : ___|   |___|   |______
+     */
+    if (gpio_init(dev->data, GPIO_OUT) == -1) {
+        return -EIO;
+    }
+
+    /* set initial state */
+    gpio_set(dev->data);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+    gpio_clear(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    gpio_set(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    gpio_clear(dev->data);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    gpio_clear(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    gpio_set(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    gpio_set(dev->data);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    gpio_clear(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    if (gpio_init(dev->data, GPIO_IN) == -1) {
+        return -EIO;
+    }
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static int connection_reset(const sht1x_dev_t *dev)
+{
+    /*       _____________________________________________________         ____
+       DATA:                                                      |_______|
+                _    _    _    _    _    _    _    _    _        ___     ___
+       SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______|   |___|   |__
+     */
+    if (gpio_init(dev->data, GPIO_OUT) == -1) {
+        return -EIO;
+    }
+
+    gpio_set(dev->data);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+    gpio_clear(dev->clk);
+    xtimer_usleep(SHT1X_HALF_CLOCK);
+
+    for (int i = 0; i < 9; i++) {
+        clk_signal(dev);
+    }
+
+    return transmission_start(dev);
+}
+
+/*---------------------------------------------------------------------------*/
+static inline uint8_t crc_initial_value(uint8_t status)
+{
+    status &= 0x07;
+
+    return (
+        ((0x01 & status) << 7) |
+        ((0x02 & status) << 5) |
+        ((0x04 & status) << 3)
+        );
+}
+
+/*---------------------------------------------------------------------------*/
+static inline uint8_t reverse_byte(uint8_t value)
+{
+    uint8_t result = (value & 0x01) << 7;
+
+    result |= (value & 0x02) << 5;
+    result |= (value & 0x04) << 3;
+    result |= (value & 0x08) << 1;
+    result |= (value & 0x10) >> 1;
+    result |= (value & 0x20) >> 3;
+    result |= (value & 0x40) >> 5;
+    result |= (value & 0x80) >> 7;
+
+    return result;
+}
+
+/*---------------------------------------------------------------------------*/
+static int measure(const sht1x_dev_t *dev, uint16_t *value, uint8_t mode)
+{
+    uint8_t data[2] = { 0, 0 };
+    int retval;
+
+    retval = transmission_start(dev);
+    if (retval != 0) {
+        return retval;
+    }
+
+    switch (write_byte(dev, mode)) {
+        case -EIO:
+            return -EIO;
+        case 0:
+            break;
+        default:
+        case 1:
+            return -EPROTO;
+    }
+
+    /* wait until sensor has finished measurement or timeout */
+    {
+        int ack = 1;
+        for (int i = 0; ack != 0; i++) {
+            if (i > SHT1X_MEASURE_TIMEOUT) {
+                return -ECANCELED;
+            }
+
+            xtimer_usleep(1000);
+            ack = gpio_read(dev->data);
+        }
+    }
+
+    /* read MSB */
+    retval = read_byte(dev, &data[0], SHT1X_ACK);
+    if (retval != 0) {
+        return retval;
+    }
+
+    /* read LSB, send ACK only if CRC checking is enabled */
+    retval = (dev->conf & SHT1X_CONF_SKIP_CRC) ? SHT1X_NO_ACK : SHT1X_ACK;
+    retval = read_byte(dev, &data[1], retval);
+    if (retval != 0) {
+        return retval;
+    }
+
+    if (!(dev->conf & SHT1X_CONF_SKIP_CRC)) {
+        uint8_t crc;
+        uint8_t expected;
+
+        retval = read_byte(dev, &crc, SHT1X_NO_ACK);
+        if (retval != 0) {
+            return retval;
+        }
+
+        expected = crc_initial_value(dev->conf);
+        expected = crc_lookup_table[expected ^ mode];
+        expected = crc_lookup_table[expected ^ data[0]];
+        expected = crc_lookup_table[expected ^ data[1]];
+        expected = reverse_byte(expected);
+        if (expected != crc) {
+            DEBUG("[sht1x] CRC expected: 0x%02x, got: 0x%02x\n"
+                  "        CRC0: 0x%02x, CMD: 0x%02x, data: {0x%02x, 0x%02x}\n",
+                  (int)expected, (int)crc,
+                  (int)crc_initial_value(dev->conf), mode,
+                  (int)data[0], (int)data[1]);
+            return -EBADMSG;
+        }
+    }
+
+    *value = (((uint16_t)data[0]) << 8) | (uint16_t)data[1];
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+int sht1x_init(sht1x_dev_t *dev, const sht1x_params_t *params)
+{
+    if (
+        !dev ||
+        !params ||
+        (((uint8_t)params->vdd) >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0]))
+        ) {
+        return -EINVAL;
+    }
+
+    dev->clk = params->clk;
+    dev->data = params->data;
+    if (gpio_init(dev->clk, GPIO_OUT) || gpio_init(dev->data, GPIO_IN)) {
+        return -EIO;
+    }
+
+    dev->temp_off = 0;
+    dev->hum_off = 0;
+    dev->conf = 0;
+    dev->vdd = (uint8_t)params->vdd;
+    return sht1x_reset(dev);
+}
+
+/*---------------------------------------------------------------------------*/
+int16_t sht1x_temperature(const sht1x_dev_t *dev, uint16_t raw)
+{
+    if (!dev || (dev->vdd >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0]))) {
+        return INT16_MIN;
+    }
+
+    int16_t d1 = sht1x_d1[dev->vdd];
+    int16_t d2 = (dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? 4 : 1;
+    return d1 + d2 * ((int16_t)raw);
+}
+
+/*---------------------------------------------------------------------------*/
+int16_t sht1x_humidity(const sht1x_dev_t *dev, uint16_t raw, int16_t temp)
+{
+    if (!dev) {
+        return -1;
+    }
+
+    static const int32_t c1 = -20468;
+    static const int32_t t1 = 1;
+    int32_t c2, c3, c4, t2;
+    if (dev->conf & SHT1X_CONF_LOW_RESOLUTION) {
+        c2 = 5872;
+        c3 = 494801;
+        c4 = 1000000;
+        t2 = 781;
+    }
+    else {
+        c2 = 367;
+        c3 = 791684;
+        c4 = 100000;
+        t2 = 12500;
+    }
+
+    /*
+     * Calculate linear humidity, but slightly different. Original formula:
+     *
+     * hum_lin = c1 + c2 * raw + c3 * (raw * raw)
+     *
+     * But we use:
+     *
+     * hum_lin = c1 + c2 * raw - (c4 * raw / c3') * (c4 * raw / c3')
+     *
+     * where: c3' = 1 / (sqrt(-c3) / c4)
+     *
+     * (This better fits for integer calculation)
+     */
+
+    int32_t res = ((int32_t)raw * c4) / c3;
+    res = c1 + c2 * (int32_t)raw - (res * res);
+
+    /*
+     * Perform temperature compensation, again slightly different.
+     * Original formula:
+     *
+     * hum_true = (temp - 25) * (t1 + t2 * raw) + hum_lin
+     *
+     * But we use:
+     *
+     * hum_true = (temp - 25) * t1 + (temp - 25) * raw / t2') + hum_lin
+     *
+     * where t2' = 1/t2
+     */
+    int32_t temp_diff = temp - 2500;
+    res = temp_diff * t1 + (temp_diff * (int32_t)raw * 100) / t2 + res;
+    return (int16_t)(res / 100);
+}
+
+
+/*---------------------------------------------------------------------------*/
+int sht1x_read(const sht1x_dev_t *dev, int16_t *temp, int16_t *rel_hum)
+{
+    uint16_t temp_raw;
+    int16_t t;
+    uint16_t hum_raw;
+    int retval;
+
+    if (
+        !dev ||
+        (dev->vdd >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0])) ||
+        (!temp && !rel_hum)
+        ) {
+        return -EINVAL;
+    }
+
+    retval = measure(dev, &temp_raw, SHT1X_MEASURE_TEMP);
+    if (retval != 0) {
+        connection_reset(dev);
+        return retval;
+    }
+
+    t = sht1x_temperature(dev, temp_raw) + dev->temp_off;
+
+    if (temp != NULL) {
+        *temp = t;
+    }
+
+    if (rel_hum != NULL) {
+        retval = measure(dev, &hum_raw, SHT1X_MEASURE_HUM);
+        if (retval != 0) {
+            connection_reset(dev);
+            return retval;
+        }
+
+        *rel_hum = sht1x_humidity(dev, hum_raw, t) + dev->hum_off;
+    }
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+int sht1x_configure(sht1x_dev_t *dev, sht1x_conf_t conf)
+{
+    if (!dev) {
+        return -EINVAL;
+    }
+
+    /* Apply config that is not stored on the sensor */
+    dev->conf &= SHT1X_CONF_MASK;
+    dev->conf |= conf & (~(SHT1X_CONF_MASK));
+
+    /* Send new status byte to sensor, if on-device config was changed */
+    if ((conf & SHT1X_CONF_MASK) != (dev->conf & SHT1X_CONF_MASK)) {
+        int retval = transmission_start(dev);
+        if (retval != 0) {
+            return retval;
+        }
+
+        switch (write_byte(dev, SHT1X_STATUS_REG_W)) {
+            case -EIO:
+                return -EIO;
+            case 0:
+                break;
+            default:
+            case 1:
+                return -EPROTO;
+        }
+
+        switch (write_byte(dev, conf & SHT1X_CONF_MASK)) {
+            case -EIO:
+                return -EIO;
+            case 0:
+                break;
+            default:
+            case 1:
+                return -EPROTO;
+        }
+
+        /* Read back uploaded configuration to verify that sensor applied it */
+        uint8_t status;
+        retval = sht1x_read_status(dev, &status);
+        if (retval != 0) {
+            return retval;
+        }
+        if (dev->conf != conf) {
+            /* Configuration was not applied by sensor */
+            return -ECANCELED;
+        }
+    }
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+int sht1x_read_status(sht1x_dev_t *dev, uint8_t *status)
+{
+    int retval;
+
+    if (!dev || !status) {
+        return -EINVAL;
+    }
+
+    retval = transmission_start(dev);
+    if (retval != 0) {
+        return retval;
+    }
+
+    switch (write_byte(dev, SHT1X_STATUS_REG_R)) {
+        case -EIO:
+            return -EIO;
+        case 0:
+            break;
+        default:
+        case 1:
+            return -EPROTO;
+    }
+
+    retval = read_byte(dev, status, SHT1X_ACK);
+    if (retval != 0) {
+        return retval;
+    }
+
+    {
+        uint8_t crc;
+        uint8_t expected;
+        /* read checksum */
+        retval = read_byte(dev, &crc, SHT1X_NO_ACK);
+        if (retval != 0) {
+            return retval;
+        }
+
+        expected = crc_initial_value(*status);
+        expected = crc_lookup_table[expected ^ SHT1X_STATUS_REG_R];
+        expected = crc_lookup_table[expected ^ *status];
+        expected = reverse_byte(expected);
+        if (expected != crc) {
+            DEBUG("[sht1x] CRC expected: 0x%02x, got: 0x%02x\n"
+                  "        CRC0: 0x%02x, CMD: 0x%02x, data: {0x%02x}\n",
+                  (int)expected, (int)crc,
+                  (int)crc_initial_value(*status), SHT1X_STATUS_REG_R,
+                  (int)*status);
+            return -EBADMSG;
+        }
+    }
+
+    /* Extract config from status and store it after CRC check passed */
+    dev->conf &= ~(SHT1X_CONF_MASK);
+    dev->conf |= *status & SHT1X_CONF_MASK;
+
+    return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+int sht1x_reset(sht1x_dev_t *dev)
+{
+    int retval;
+
+    if (!dev) {
+        return -EINVAL;
+    }
+
+    retval = transmission_start(dev);
+    if (retval != 0) {
+        return retval;
+    }
+
+    switch (write_byte(dev, SHT1X_RESET)) {
+        case -EIO:
+            return -EIO;
+        case 0:
+            break;
+        default:
+        case 1:
+            return -EPROTO;
+    }
+
+    dev->conf = 0;
+    xtimer_usleep(SHT1X_RESET_WAIT);
+
+    return 0;
+}
diff --git a/drivers/sht1x/sht1x_saul.c b/drivers/sht1x/sht1x_saul.c
new file mode 100644
index 0000000000000000000000000000000000000000..7c0abd92551c7178b4da06e173c908aafe42b785
--- /dev/null
+++ b/drivers/sht1x/sht1x_saul.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     drivers_sht1x
+ * @{
+ *
+ * @file
+ * @brief       SAUL adaption for SHT10/SHT11/SHT15 devices
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ *
+ * @}
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "phydat.h"
+#include "saul.h"
+#include "sht1x_defines.h"
+#include "sht1x.h"
+
+static int read(const sht1x_dev_t *dev, int16_t *temp, int16_t *hum)
+{
+    for (int retries = 0; retries < SHT1X_SAUL_RETRIES; retries++) {
+        switch (sht1x_read(dev, temp, hum)) {
+            case 0:
+                return 0;
+            case -EBADMSG:
+                puts("[sht1x] CRC");
+                continue;
+            case -EPROTO:
+                puts("[sht1x] Sensor did not acknowledge measurement command");
+                continue;
+            case -ECANCELED:
+                puts("[sht1x] Measurement times out");
+            default:
+                /* Other failure, cannot recover so giving up */
+                return -1;
+        }
+    }
+
+    printf("[sht1x] Giving up after %i tries\n", SHT1X_SAUL_RETRIES);
+
+    return -1;
+}
+
+static int read_temp(const void *dev, phydat_t *res)
+{
+    if (read(dev, &res->val[0], NULL) == 0) {
+        res->unit = UNIT_TEMP_C;
+        res->scale = -2;
+        return 1;
+    }
+
+    return -ECANCELED;
+}
+
+static int read_hum(const void *dev, phydat_t *res)
+{
+    if (read(dev, NULL, &res->val[0]) == 0) {
+        res->unit = UNIT_PERCENT;
+        res->scale = -2;
+        return 1;
+    }
+
+    return -ECANCELED;
+}
+
+const saul_driver_t sht1x_saul_temp_driver = {
+    .read = read_temp,
+    .write = saul_notsup,
+    .type = SAUL_SENSE_TEMP
+};
+
+const saul_driver_t sht1x_saul_hum_driver = {
+    .read = read_hum,
+    .write = saul_notsup,
+    .type = SAUL_SENSE_HUM
+};
diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk
index 1e3d3198985a4150e2374ae818a85333c828de4d..0d04d3cec7c6e1f84dd6ae2aa2a37df5051c9e69 100644
--- a/makefiles/pseudomodules.inc.mk
+++ b/makefiles/pseudomodules.inc.mk
@@ -95,6 +95,11 @@ PSEUDOMODULES += adc121c
 PSEUDOMODULES += sx1272
 PSEUDOMODULES += sx1276
 
+# include variants of SHT1X drivers as pseudo modules
+PSEUDOMODULES += sht10
+PSEUDOMODULES += sht11
+PSEUDOMODULES += sht15
+
 # include variants of Si114x drivers as pseudo modules
 PSEUDOMODULES += si1145
 PSEUDOMODULES += si1146
diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c
index 8287a2568ca327c00b8ab2dd5c1bcb7d978d3d2b..64d06a3a9f4819acf57ff361a6be389bc92ddda5 100644
--- a/sys/auto_init/auto_init.c
+++ b/sys/auto_init/auto_init.c
@@ -20,10 +20,6 @@
 
 #include "auto_init.h"
 
-#ifdef MODULE_SHT11
-#include "sht11.h"
-#endif
-
 #ifdef MODULE_MCI
 #include "diskio.h"
 #endif
@@ -101,10 +97,6 @@ void auto_init(void)
     DEBUG("Auto init xtimer module.\n");
     xtimer_init();
 #endif
-#ifdef MODULE_SHT11
-    DEBUG("Auto init SHT11 module.\n");
-    sht11_init();
-#endif
 #ifdef MODULE_MCI
     DEBUG("Auto init mci module.\n");
     mci_initialize();
@@ -275,6 +267,12 @@ void auto_init(void)
 #endif
 
 /* initialize sensors and actuators */
+#ifdef MODULE_SHT1X
+    DEBUG("Auto init SHT1X module (SHT10/SHT11/SHT15 sensor driver).\n");
+    extern void auto_init_sht1x(void);
+    auto_init_sht1x();
+#endif
+
 #ifdef MODULE_AUTO_INIT_SAUL
     DEBUG("auto_init SAUL\n");
 
diff --git a/sys/auto_init/auto_init_sht1x.c b/sys/auto_init/auto_init_sht1x.c
new file mode 100644
index 0000000000000000000000000000000000000000..3264ab9b45ed0c8446d4cc5ce98e3952f9d5130b
--- /dev/null
+++ b/sys/auto_init/auto_init_sht1x.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ *
+ */
+
+/*
+ * @ingroup sys_auto_init
+ * @{
+ *
+ * @file
+ * @brief       Auto initialization for SHT1X temperature/humidity sensors
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ *
+ * @}
+ */
+
+#ifdef MODULE_SHT1X
+
+#include "log.h"
+#include "sht1x_params.h"
+#include "sht1x.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+/**
+ * @brief   Define the number of configured sensors
+ */
+#define SHT1X_NUM     (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
+
+/**
+ * @brief   Allocate memory for the device descriptors
+ */
+sht1x_dev_t sht1x_devs[SHT1X_NUM];
+
+#ifdef MODULE_AUTO_INIT_SAUL
+
+/**
+ * @brief   Memory for the SAUL registry entries
+ */
+static saul_reg_t saul_entries[SHT1X_NUM * 2];
+
+/**
+ * @name    Import SAUL endpoints
+ * @{
+ */
+extern const saul_driver_t sht1x_saul_temp_driver;
+extern const saul_driver_t sht1x_saul_hum_driver;
+/** @} */
+
+#endif /* MODULE_AUTO_INIT_SAUL */
+
+static void sht1x_error(unsigned int num, const char *reason)
+{
+    LOG_ERROR("[auto_init] error initializing SHT10/SHT11/SHT15 sensor "
+              "#%u: %s\n", num, reason);
+}
+
+void auto_init_sht1x(void)
+{
+    for (unsigned int i = 0; i < SHT1X_NUM; i++) {
+        DEBUG("[auto_init_sht1x] Initializing SHT1X sensor #%u\n", i);
+
+        switch (sht1x_init(&sht1x_devs[i], &sht1x_params[i])) {
+            case 0:
+                break;
+            case -EIO:
+                sht1x_error(i, "Failed to initialize GPIOs");
+                continue;
+            case -EINVAL:
+                sht1x_error(i, "Invalid configuration for VDD");
+                continue;
+            case -EPROTO:
+                sht1x_error(i, "Reset command not acknowledged");
+                continue;
+            default:
+                /* Should not happen, but better safe than sorry */
+                sht1x_error(i, "?");
+                continue;
+        }
+
+#ifdef MODULE_AUTO_INIT_SAUL
+        saul_entries[(i * 2)    ].dev = &(sht1x_devs[i]);
+        saul_entries[(i * 2) + 1].dev = &(sht1x_devs[i]);
+        saul_entries[(i * 2)    ].name = sht1x_saul_info[(i * 2)    ].name;
+        saul_entries[(i * 2) + 1].name = sht1x_saul_info[(i * 2) + 1].name;
+        saul_entries[(i * 2)    ].driver = &sht1x_saul_temp_driver;
+        saul_entries[(i * 2) + 1].driver = &sht1x_saul_hum_driver;
+        saul_reg_add(&(saul_entries[(i * 2)    ]));
+        saul_reg_add(&(saul_entries[(i * 2) + 1]));
+#endif /* MODULE_AUTO_INIT_SAUL */
+    }
+}
+
+#else
+typedef int dont_be_pedantic;
+#endif /* MODULE_SHT1X */
diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile
index 8e8e56e3d9fc46427e64ca3c23d35c419bebb618..5d1908f2d13e9c4d903f37aab68495b514688e7d 100644
--- a/sys/shell/commands/Makefile
+++ b/sys/shell/commands/Makefile
@@ -8,8 +8,8 @@ endif
 ifneq (,$(filter ps,$(USEMODULE)))
   SRC += sc_ps.c
 endif
-ifneq (,$(filter sht11,$(USEMODULE)))
-  SRC += sc_sht11.c
+ifneq (,$(filter sht1x,$(USEMODULE)))
+  SRC += sc_sht1x.c
 endif
 ifneq (,$(filter lpc2387,$(USEMODULE)))
   SRC += sc_heap.c
diff --git a/sys/shell/commands/sc_sht11.c b/sys/shell/commands/sc_sht11.c
deleted file mode 100644
index 6722626125bfb714a320248cca28e11d53fae7fd..0000000000000000000000000000000000000000
--- a/sys/shell/commands/sc_sht11.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2013  INRIA.
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-/**
- * @ingroup     sys_shell_commands
- * @{
- *
- * @file
- * @brief       Provides shell commands to poll sht11 sensor
- *
- * @author      Oliver Hahm <oliver.hahm@inria.fr>
- *
- * @}
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include "sht11.h"
-
-#ifdef MODULE_SHT11
-
-extern float sht11_temperature_offset;
-
-int _get_humidity_handler(int argc, char **argv)
-{
-    (void) argc;
-    (void) argv;
-
-    uint8_t success;
-    sht11_val_t sht11_val;
-    success = sht11_read_sensor(&sht11_val, HUMIDITY | TEMPERATURE);
-
-    if (!success) {
-        printf("Error reading SHT11\n");
-
-        return 1;
-    }
-    else {
-        printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%%\n",
-               (double) sht11_val.relhum, (double) sht11_val.relhum_temp);
-
-        return 0;
-    }
-}
-
-int _get_temperature_handler(int argc, char **argv)
-{
-    (void) argc;
-    (void) argv;
-
-    uint8_t success;
-    sht11_val_t sht11_val;
-    success = sht11_read_sensor(&sht11_val, TEMPERATURE);
-
-    if (!success) {
-        printf("Error reading SHT11\n");
-
-        return 1;
-    }
-    else {
-        printf("Temperature: %-6.2f°C\n", (double) sht11_val.temperature);
-
-        return 0;
-    }
-}
-
-int _get_weather_handler(int argc, char **argv)
-{
-    (void) argc;
-    (void) argv;
-
-    uint8_t success;
-    sht11_val_t sht11_val;
-    success = sht11_read_sensor(&sht11_val, HUMIDITY | TEMPERATURE);
-
-    if (!success) {
-        printf("Error reading SHT11\n");
-
-        return 1;
-    }
-    else {
-        printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%% ",
-               (double) sht11_val.relhum, (double) sht11_val.relhum_temp);
-        printf("Temperature: %-6.2f°C\n", (double) sht11_val.temperature);
-
-        return 0;
-    }
-}
-
-int _set_offset_handler(int argc, char **argv)
-{
-    if (argc != 2) {
-        printf("Usage: %s <OFFSET>\n", argv[0]);
-
-        return 1;
-    }
-    else {
-        sht11_temperature_offset = atoi(argv[1]);
-        printf("Temperature offset set to %f\n", (double) sht11_temperature_offset);
-
-        return 0;
-    }
-}
-
-#endif
diff --git a/sys/shell/commands/sc_sht1x.c b/sys/shell/commands/sc_sht1x.c
new file mode 100644
index 0000000000000000000000000000000000000000..c814ccff484d7afb4a89ece2bfaa535377657b53
--- /dev/null
+++ b/sys/shell/commands/sc_sht1x.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2013 INRIA
+ *               2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     sys_shell_commands
+ * @{
+ *
+ * @file
+ * @brief       Provides shell commands to access SHT10/SHT11/SHT15 sensors
+ *
+ * @author      Oliver Hahm <oliver.hahm@inria.fr>
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ *
+ * @}
+ */
+
+#ifdef MODULE_SHT1X
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sht1x.h"
+#include "sht1x_params.h"
+
+#define SHT1X_NUM     (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
+
+extern sht1x_dev_t sht1x_devs[SHT1X_NUM];
+
+static sht1x_dev_t *get_dev(int argc, char **argv)
+{
+    switch (argc) {
+        case 1:
+            return &sht1x_devs[0];
+        case 2:
+        {
+            int pos = atoi(argv[1]);
+            if ((pos < 0) || (pos >= (int)SHT1X_NUM)) {
+                printf("No SHT10/SHT11/SHT15 device with number %i\n", pos);
+                return NULL;
+            }
+            return &sht1x_devs[pos];
+        }
+        default:
+            break;
+    }
+
+    printf("Usage: %s [DEVICE_NUMBER]\n", argv[0]);
+    return NULL;
+}
+
+static void error_msg(const char *msg)
+{
+    printf("[sht1x] Operation failed: %s\n", msg);
+}
+
+static int read_sensor(int16_t *temp, int16_t *hum, int argc, char **argv)
+{
+    const sht1x_dev_t *dev = get_dev(argc, argv);
+
+    if (!dev) {
+        return -1;
+    }
+
+    switch (sht1x_read(dev, temp, hum)) {
+        case 0:
+            break;
+        case -EIO:
+            error_msg("gpio_init() failed");
+            return -1;
+        case -EBADMSG:
+            error_msg("CRC checksum error");
+            return -1;
+        case -ECANCELED:
+            error_msg("Measurement timed out");
+            return -1;
+        case -EPROTO:
+            error_msg("Sensor did not acknowledge command");
+            return -1;
+        default:
+            /* Should never happen, but better safe the sorry */
+            error_msg("Unknown error");
+            return -1;
+    }
+
+    return 0;
+}
+
+int _get_humidity_handler(int argc, char **argv)
+{
+    int16_t hum;
+
+    if (read_sensor(NULL, &hum, argc, argv)) {
+        return -1;
+    }
+
+    printf("Relative humidity: %i.%02i%%\n", (int)hum / 100, (int)hum % 100);
+    return 0;
+}
+
+int _get_temperature_handler(int argc, char **argv)
+{
+    int16_t temp;
+
+    if (read_sensor(&temp, NULL, argc, argv)) {
+        return -1;
+    }
+
+    printf("Temperature: %i.%02i°C\n", (int)temp / 100, (int)temp % 100);
+    return 0;
+}
+
+int _get_weather_handler(int argc, char **argv)
+{
+    int16_t hum;
+    int16_t temp;
+
+    if (read_sensor(&temp, &hum, argc, argv)) {
+        return -1;
+    }
+
+    printf("Relative humidity: %i.%02i%%\n", (int)hum / 100, (int)hum % 100);
+    printf("Temperature: %i.%02i°C\n", (int)temp / 100, (int)temp % 100);
+    return 0;
+}
+
+static void print_config(const sht1x_dev_t *dev)
+{
+    const char *vdds[] = { "5.0", "4.0", "3.5", "3.0", "2.5" };
+
+    printf("Sensor VDD = %s\n", vdds[dev->vdd]);
+    printf("Temperature offset [-t]: %i\n", (int)dev->temp_off);
+    printf("Humidity offset [-h]: %i\n", (int)dev->hum_off);
+    printf("Resolution [-r]: %s\n",
+           (dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? "low" : "high");
+    printf("Skip calibration (faster reading) [-c]: %s\n",
+           (dev->conf & SHT1X_CONF_SKIP_CALIBRATION) ? "yes" : "no");
+    printf("Heater [-H]: %s\n",
+           (dev->conf & SHT1X_CONF_ENABLE_HEATER) ? "on" : "off");
+    printf("CRC checking [-C]: %s\n",
+           (dev->conf & SHT1X_CONF_SKIP_CRC) ? "off" : "on");
+}
+
+static void unknown_parameter(int index, char **argv)
+{
+    printf("Unknown parameter \"%s\"\n"
+           "Usage: \"%s [PARAMS]\", run \"%s --help\" for help\n",
+           argv[index], argv[0], argv[0]);
+}
+
+static void missing_argument(int index, char **argv)
+{
+    printf("Missing argument for parameter \"%s\"\n"
+           "Usage: \"%s [%s <ARG>][PARAMS]\", run \"%s --help\" for help\n",
+           argv[index], argv[0], argv[index], argv[0]);
+}
+
+static void invalid_argument(int index, char **argv, const char *valid)
+{
+    printf("Invalid argument \"%s\" for parameter \"%s\"\n"
+           "Valid arguments are: \"%s\", run \"%s --help\" for help\n",
+           argv[index + 1], argv[index], valid, argv[0]);
+}
+
+int _sht_config_handler(int argc, char **argv)
+{
+    uint8_t set_conf = 0;
+    uint8_t unset_conf = 0;
+    int16_t temp_off = INT16_MAX;
+    int16_t hum_off = INT16_MAX;
+    int dev_num = 0;
+
+    if ((argc == 2) && (strcmp("--help", argv[1]) == 0)) {
+        printf("Usage: \"%s [PARMS]\n"
+               "\n"
+               "Supported parameters:\n"
+               "  -d <NUM>\n"
+               "    Use SHT10/11/15 sensor number <NUM>. Default: 0\n"
+               "\n"
+               "  -t <OFFSET>\n"
+               "    Add <OFFSET> (in e-2°C) to all temperature measurements\n"
+               "\n"
+               "  -h <OFFSET>\n"
+               "    Add <OFFSET> (in e-2%%) to all humidity measurements\n"
+               "\n"
+               "  -r l/h\n"
+               "    Set resolution to low/high. Low resolution trades "
+               "presicion for speed\n"
+               "\n"
+               "  -H y/n\n"
+               "    Turns heater on/off. Can increase temperature by up to "
+               "10°C\n"
+               "\n"
+               "  -C y/n\n"
+               "    Turns on/off CRC checking. No checking trades robustness "
+               "for speed\n",
+               argv[0]);
+        return 0;
+    }
+
+    for (int i = 1; i < argc; i++) {
+        if ((argv[i][0] != '-') || (!argv[i][1]) || (argv[i][2])) {
+            unknown_parameter(i, argv);
+            return -1;
+        }
+
+        switch (argv[i][1]) {
+            case 'd':
+                if (++i >= argc) {
+                    missing_argument(i - 1, argv);
+                    return -1;
+                }
+                dev_num = atoi(argv[i]);
+                if ((dev_num < 0) || (dev_num >= (int)SHT1X_NUM)) {
+                    printf("No SHT10/11/15 sensor with number %i\n", dev_num);
+                    return -1;
+                }
+                break;
+            case 't':
+                if (++i >= argc) {
+                    missing_argument(i - 1, argv);
+                    return -1;
+                }
+                temp_off = (int16_t)atoi(argv[i]);
+                break;
+            case 'h':
+                if (++i >= argc) {
+                    missing_argument(i - 1, argv);
+                    return -1;
+                }
+                hum_off = (int16_t)atoi(argv[i]);
+                break;
+            case 'r':
+                if (++i >= argc) {
+                    missing_argument(i - 1, argv);
+                    return -1;
+                }
+                if ((!argv[i][0]) || (argv[i][1])) {
+                    invalid_argument(i - 1, argv, "l, h");
+                    return -1;
+                }
+                switch (argv[i][0]) {
+                    case 'l':
+                        set_conf |= SHT1X_CONF_LOW_RESOLUTION;
+                        break;
+                    case 'h':
+                        unset_conf |= SHT1X_CONF_LOW_RESOLUTION;
+                        break;
+                    default:
+                        invalid_argument(i - 1, argv, "l, h");
+                        return -1;
+                }
+                break;
+            case 'c':
+                if (++i >= argc) {
+                    missing_argument(i - 1, argv);
+                    return -1;
+                }
+                if ((!argv[i][0]) || (argv[i][1])) {
+                    invalid_argument(i - 1, argv, "y, n");
+                    return -1;
+                }
+                switch (argv[i][0]) {
+                    case 'y':
+                        set_conf |= SHT1X_CONF_SKIP_CALIBRATION;
+                        break;
+                    case 'n':
+                        unset_conf |= SHT1X_CONF_SKIP_CALIBRATION;
+                        break;
+                    default:
+                        invalid_argument(i - 1, argv, "y, n");
+                        return -1;
+                }
+                break;
+            case 'H':
+                if (++i >= argc) {
+                    missing_argument(i - 1, argv);
+                    return -1;
+                }
+                if ((!argv[i][0]) || (argv[i][1])) {
+                    invalid_argument(i - 1, argv, "y, n");
+                    return -1;
+                }
+                switch (argv[i][0]) {
+                    case 'y':
+                        set_conf |= SHT1X_CONF_ENABLE_HEATER;
+                        break;
+                    case 'n':
+                        unset_conf |= SHT1X_CONF_ENABLE_HEATER;
+                        break;
+                    default:
+                        invalid_argument(i - 1, argv, "y, n");
+                        return -1;
+                }
+                break;
+            case 'C':
+                if (++i >= argc) {
+                    missing_argument(i - 1, argv);
+                    return -1;
+                }
+                if ((!argv[i][0]) || (argv[i][1])) {
+                    invalid_argument(i - 1, argv, "y, n");
+                    return -1;
+                }
+                switch (argv[i][0]) {
+                    case 'y':
+                        unset_conf |= SHT1X_CONF_SKIP_CRC;
+                        break;
+                    case 'n':
+                        set_conf |= SHT1X_CONF_SKIP_CRC;
+                        break;
+                    default:
+                        invalid_argument(i - 1, argv, "y, n");
+                        return -1;
+                }
+                break;
+            default:
+                unknown_parameter(i, argv);
+                return -1;
+        }
+    }
+
+    if ((set_conf) || (unset_conf)) {
+        /* Apply new configuration */
+        uint8_t new_conf = sht1x_devs[dev_num].conf;
+        new_conf &= ~(unset_conf);
+        new_conf |= set_conf;
+        switch (sht1x_configure(&sht1x_devs[dev_num], new_conf)) {
+            case 0:
+                break;
+            case -EIO:
+                error_msg("gpio_init() failed");
+                return -1;
+            case -EBADMSG:
+                error_msg("CRC checksum error");
+                return -1;
+            case -ECANCELED:
+                error_msg("Sensor did not apply configuration");
+                return -1;
+            case -EPROTO:
+                error_msg("Sensor did not acknowledge command");
+                return -1;
+            default:
+                /* Should never happen, but better safe the sorry */
+                error_msg("Unknown error");
+                return -1;
+        }
+    }
+
+    if (temp_off != INT16_MAX) {
+        if ((temp_off > 2000) || (temp_off < -2000)) {
+            printf("A temperature offset of %i.%02i°C is unreasonable\n",
+                   (int)temp_off / 100, (int)temp_off % 100);
+            return -1;
+        }
+        sht1x_devs[dev_num].temp_off = temp_off;
+    }
+
+    if (hum_off != INT16_MAX) {
+        if ((hum_off > 1000) || (hum_off < -1000)) {
+            printf("A humidity offset of %i.%02i%% is unreasonable\n",
+                   (int)hum_off / 100, (int)hum_off % 100);
+            return -1;
+        }
+        sht1x_devs[dev_num].hum_off = hum_off;
+    }
+
+    print_config(&sht1x_devs[dev_num]);
+    return 0;
+}
+
+#endif
diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c
index 6ab2937dc293f0a4520237fce81cbe1501ee96ea..a9871517d3e64da7b5cdbd5642db37827d1f3e27 100644
--- a/sys/shell/commands/shell_commands.c
+++ b/sys/shell/commands/shell_commands.c
@@ -37,11 +37,11 @@ extern int _heap_handler(int argc, char **argv);
 extern int _ps_handler(int argc, char **argv);
 #endif
 
-#ifdef MODULE_SHT11
+#ifdef MODULE_SHT1X
 extern int _get_temperature_handler(int argc, char **argv);
 extern int _get_humidity_handler(int argc, char **argv);
 extern int _get_weather_handler(int argc, char **argv);
-extern int _set_offset_handler(int argc, char **argv);
+extern int _sht_config_handler(int argc, char **argv);
 #endif
 
 #ifdef MODULE_LTC4150
@@ -153,11 +153,11 @@ const shell_command_t _shell_command_list[] = {
 #ifdef MODULE_PS
     {"ps", "Prints information about running threads.", _ps_handler},
 #endif
-#ifdef MODULE_SHT11
+#ifdef MODULE_SHT1X
     {"temp", "Prints measured temperature.", _get_temperature_handler},
     {"hum", "Prints measured humidity.", _get_humidity_handler},
     {"weather", "Prints measured humidity and temperature.", _get_weather_handler},
-    {"offset", "Set temperature offset.", _set_offset_handler},
+    {"sht-config", "Get/set SHT10/11/15 sensor configuration.", _sht_config_handler},
 #endif
 #ifdef MODULE_LTC4150
     {"cur", "Prints current and average power consumption.", _get_current_handler},
diff --git a/tests/driver_sht1x/Makefile b/tests/driver_sht1x/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..4c51663c52712d0b4b7e8688d150334739cd430a
--- /dev/null
+++ b/tests/driver_sht1x/Makefile
@@ -0,0 +1,12 @@
+include ../Makefile.tests_common
+
+DRIVER ?= sht11
+BOARD ?= msba2
+
+USEMODULE += $(DRIVER)
+USEMODULE += shell
+USEMODULE += saul_default
+USEMODULE += shell_commands
+USEMODULE += ps
+
+include $(RIOTBASE)/Makefile.include
diff --git a/tests/driver_sht1x/main.c b/tests/driver_sht1x/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..864ce7f6a2e9173a8d336fad82b784db1fb2c012
--- /dev/null
+++ b/tests/driver_sht1x/main.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     tests
+ * @{
+ *
+ * @file
+ * @brief       Test application for the SHT10/11/15 family of temperature and
+ *              humidity sensors
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ *
+ * @}
+ */
+
+#include <stdio.h>
+
+#include "shell.h"
+#include "shell_commands.h"
+#include "sht1x_params.h"
+
+#define SHT1X_NUM     (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
+extern sht1x_dev_t sht1x_devs[SHT1X_NUM];
+static sht1x_dev_t *dev = &sht1x_devs[0];
+
+static int run_tests(void)
+{
+    const char *resolution[] = { "high", "low" };
+    const char *calibration[] = { "on", "off" };
+    const char *heater[] = { "off", "on" };
+    const char *crc[] = { "on", "off" };
+    uint8_t conf = 0;
+
+    puts("Reading the sensor three times for all possible configurations:");
+
+    for (int i_res = 0; i_res < 2; i_res++) {
+        if (i_res) {
+            conf |= SHT1X_CONF_LOW_RESOLUTION;
+        }
+        else {
+            conf &= ~(SHT1X_CONF_LOW_RESOLUTION);
+        }
+
+        for (int i_cal = 0; i_cal < 2; i_cal++) {
+            if (i_cal) {
+                conf |= SHT1X_CONF_SKIP_CALIBRATION;
+            }
+            else {
+                conf &= ~(SHT1X_CONF_SKIP_CALIBRATION);
+            }
+
+            for (int i_heater = 0; i_heater < 2; i_heater++) {
+                if (i_heater) {
+                    conf |= SHT1X_CONF_ENABLE_HEATER;
+                }
+                else {
+                    conf &= ~(SHT1X_CONF_ENABLE_HEATER);
+                }
+
+                for (int i_crc = 0; i_crc < 2; i_crc++) {
+                    if (i_crc) {
+                        conf |= SHT1X_CONF_SKIP_CRC;
+                    }
+                    else {
+                        conf &= ~(SHT1X_CONF_SKIP_CRC);
+                    }
+
+                    printf("Resolution: %s, calibration: %s, heater: %s, "
+                           "CRC-checking: %s\n",
+                           resolution[i_res],
+                           calibration[i_cal],
+                           heater[i_heater],
+                           crc[i_crc]);
+                    switch (sht1x_configure(dev, conf)) {
+                        case 0:
+                            break;
+                        case -EIO:
+                            puts("Error: gpio_init() failed");
+                            return -1;
+                        case -EPROTO:
+                            puts("Error: Sensor did not acknowledge command");
+                            return -1;
+                        case -ECANCELED:
+                            puts("Error: Sensor did not apply configuration");
+                            return -1;
+                        case -EBADMSG:
+                            puts("Error: CRC error while validating "
+                                 "configuration");
+                            return -1;
+                        default:
+                            /* Will never happen, but better safe than sorry */
+                            puts("Unknown error");
+                            return -1;
+                    }
+
+                    for (int i = 0; i < 3; i++) {
+                        int16_t temp, hum;
+                        switch (sht1x_read(dev, &temp, &hum)) {
+                            case 0:
+                                break;
+                            case -EIO:
+                                puts("Error: gpio_init() failed");
+                                return -1;
+                            case -EPROTO:
+                                puts("Error: Sensor did not acknowledge "
+                                     "command");
+                                return -1;
+                            case -ECANCELED:
+                                puts("Error: Measurement timed out");
+                                return -1;
+                            default:
+                                /* Won't happen, but better safe than sorry */
+                                puts("Unknown error");
+                                return -1;
+                        }
+
+                        printf("Temperature: %i.%02i°C, Humidity: %i.%02i%%\n",
+                               (int)temp / 100, (int)temp % 100,
+                               (int)hum / 100, (int)hum % 100);
+                    }
+                }
+            }
+        }
+    }
+
+    puts("Restoring default configuration");
+    switch (sht1x_configure(dev, 0)) {
+        case 0:
+            break;
+        case -EIO:
+            puts("Error: gpio_init() failed");
+            return -1;
+        case -EPROTO:
+            puts("Error: Sensor did not acknowledge command");
+            return -1;
+        case -ECANCELED:
+            puts("Error: Sensor did not apply configuration");
+            return -1;
+        case -EBADMSG:
+            puts("Error: CRC error while validating "
+                 "configuration");
+            return -1;
+        default:
+            /* Will never happen, but better safe than sorry */
+            puts("Unknown error");
+            return -1;
+    }
+
+    return 0;
+}
+
+int main(void)
+{
+    if (run_tests()) {
+        puts("TESTS FAILED!");
+    }
+    else {
+        puts("All automatic tests finished.");
+    }
+
+    puts("Dropping to shell for manual testing");
+    char line_buf[SHELL_DEFAULT_BUFSIZE];
+    shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
+
+    return 0;
+}
diff --git a/tests/unittests/tests-sht1x/Makefile b/tests/unittests/tests-sht1x/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2
--- /dev/null
+++ b/tests/unittests/tests-sht1x/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/tests/unittests/tests-sht1x/Makefile.include b/tests/unittests/tests-sht1x/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..4ccfa29f725f5639114c15e1fc0022c3c74308d5
--- /dev/null
+++ b/tests/unittests/tests-sht1x/Makefile.include
@@ -0,0 +1 @@
+USEMODULE += sht1x
diff --git a/tests/unittests/tests-sht1x/tests-sht1x.c b/tests/unittests/tests-sht1x/tests-sht1x.c
new file mode 100644
index 0000000000000000000000000000000000000000..3991db589c8f5b9878d2a214baa0474fd9ed324f
--- /dev/null
+++ b/tests/unittests/tests-sht1x/tests-sht1x.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+#include <sht1x.h>
+#include <stdlib.h>
+#include "embUnit/embUnit.h"
+#include "tests-sht1x.h"
+
+/** @brief Maximum difference from correct temperature value [in e-02 °C] */
+static const int16_t max_diff_temp = 1;
+/** @brief Maximum difference from correct humidity value [in e-02 %] */
+static const int16_t max_diff_hum = 10;
+
+static int16_t expected_temp(const sht1x_dev_t *dev, uint16_t _raw)
+{
+    static const double d1_table[] = { -40.1, -39.8, -39.7, -39.6, -39.4 };
+    double d1 = d1_table[dev->vdd];
+    double d2 = (dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? 0.04 : 0.01;
+    double raw = (double)_raw;
+    double temp = d1 + d2 * raw;
+
+    return (int16_t)(temp * 100.0);
+}
+
+static int16_t expected_hum(const sht1x_dev_t *dev, uint16_t _raw, int16_t _temp)
+{
+    static const double c1 = -2.0468;
+    static const double t1 = 0.01;
+    double temp = ((double)_temp) / 100.0;
+    double raw = (double)_raw;
+    double c2, c3, t2, hum_linear, hum_real;
+
+    if (dev->conf & SHT1X_CONF_LOW_RESOLUTION) {
+        c2 = 0.5872;
+        c3 = -4.0845e-04;
+        t2 = 0.00128;
+    }
+    else {
+        c2 = 0.0367;
+        c3 = -1.5955e-06;
+        t2 = 0.00008;
+    }
+
+    hum_linear = c1 + c2 * raw + c3 * (raw * raw);
+    hum_real = (temp - 25.0) * (t1 + t2 * raw) + hum_linear;
+    return (int16_t)(hum_real * 100.0);
+}
+
+static void test_sht1x_conversion(void)
+{
+    const uint8_t vdds[] = {
+        SHT1X_VDD_5_0V, SHT1X_VDD_4_0V, SHT1X_VDD_3_5V, SHT1X_VDD_3_0V,
+        SHT1X_VDD_2_5V,
+    };
+    const uint8_t confs[] = { SHT1X_CONF_LOW_RESOLUTION, 0 };
+    const uint16_t max_raw_temps[] = { 0xfff, 0x3fff };
+    const uint16_t max_raw_hums[] = { 0xff, 0xfff };
+    sht1x_dev_t dev = { .conf = 0 };
+
+    for (size_t i_res = 0; i_res < sizeof(confs) / sizeof(confs[0]); i_res++) {
+        dev.conf = confs[i_res];
+        uint16_t max_raw_temp = max_raw_temps[i_res];
+        uint16_t max_raw_hum = max_raw_hums[i_res];
+        for (size_t i_vdd = 0; i_vdd < sizeof(vdds) / sizeof(vdds[0]); i_vdd++) {
+            dev.vdd = vdds[i_vdd];
+            for (uint16_t raw_temp = 0; raw_temp <= max_raw_temp; raw_temp++) {
+                int16_t got_temp = sht1x_temperature(&dev, raw_temp);
+                int16_t exp_temp = expected_temp(&dev, raw_temp);
+
+                TEST_ASSERT(((got_temp - max_diff_temp) <= exp_temp) &&
+                            ((got_temp + max_diff_temp) >= exp_temp));
+            }
+        }
+
+        /* Testing for temperatures in -10.00°C and 65.00°C in steps of 0.13°C */
+        for (int16_t temp = -1000; temp < 6500; temp += 13) {
+            for (uint16_t raw_hum = 0; raw_hum <= max_raw_hum; raw_hum++) {
+                int16_t exp_hum = expected_hum(&dev, raw_hum, temp);
+                if ((exp_hum < 0) || (exp_hum > 10000)) {
+                    /* Result out of range, ignore it */
+                    continue;
+                }
+                int16_t got_hum = sht1x_humidity(&dev, raw_hum, temp);
+                TEST_ASSERT(((got_hum - max_diff_hum) <= exp_hum) &&
+                            ((got_hum + max_diff_hum) >= exp_hum));
+            }
+        }
+    }
+}
+
+Test *tests_sht1x_tests(void)
+{
+    EMB_UNIT_TESTFIXTURES(fixtures) {
+        new_TestFixture(test_sht1x_conversion),
+    };
+
+    EMB_UNIT_TESTCALLER(sht1x_tests, NULL, NULL, fixtures);
+
+    return (Test *)&sht1x_tests;
+}
+
+void tests_sht1x(void)
+{
+    TESTS_RUN(tests_sht1x_tests());
+}
diff --git a/tests/unittests/tests-sht1x/tests-sht1x.h b/tests/unittests/tests-sht1x/tests-sht1x.h
new file mode 100644
index 0000000000000000000000000000000000000000..0619efc65440e9f5d46eebaf356de8f5fba631c6
--- /dev/null
+++ b/tests/unittests/tests-sht1x/tests-sht1x.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @addtogroup  unittests
+ * @{
+ *
+ * @file
+ * @brief       Unittests for the conversions used in the sht1x driver
+ *
+ * @author      Marian Buschsieweke <marian.buschsieweke@ovgu.de>
+ */
+#ifndef TESTS_SHT1X_H
+#define TESTS_SHT1X_H
+
+#include "embUnit.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief   The entry point of this test suite.
+ */
+void tests_sht1x(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* TESTS_SHT1X_H */
+/** @} */