diff --git a/examples/bmp180_i2c/Makefile b/examples/bmp180_i2c/Makefile
new file mode 100644
index 0000000..dd5eaf6
--- /dev/null
+++ b/examples/bmp180_i2c/Makefile
@@ -0,0 +1,3 @@
+PROGRAM=BMP180_Reader
+EXTRA_COMPONENTS = extras/i2c extras/bmp180
+include ../../common.mk
diff --git a/examples/bmp180_i2c/README.md b/examples/bmp180_i2c/README.md
new file mode 100644
index 0000000..21d754a
--- /dev/null
+++ b/examples/bmp180_i2c/README.md
@@ -0,0 +1,7 @@
+# I2C / BMP180 Example
+
+This example references two addtional drivers [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c) and [bmp180](https://github.com/Angus71/esp-open-rtos-driver-bmp180), which are provided in the `../../extras` folder.
+
+If you plan to use one or both of this drivers in your own projects, please check the main development pages for updated versions or reported issues.
+
+To run this example connect the BMP085/BMP180 SCL to GPIO0 and SDA to GPIO2.
diff --git a/examples/bmp180_i2c/bmp180_i2c.c b/examples/bmp180_i2c/bmp180_i2c.c
new file mode 100644
index 0000000..76b3705
--- /dev/null
+++ b/examples/bmp180_i2c/bmp180_i2c.c
@@ -0,0 +1,132 @@
+/* Simple example for I2C / BMP180 / Timer & Event Handling
+ *
+ * This sample code is in the public domain.
+ */
+#include "espressif/esp_common.h"
+#include "espressif/sdk_private.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+#include "queue.h"
+
+// BMP180 driver
+#include "bmp180/bmp180.h"
+
+#define MY_EVT_TIMER  0x01
+#define MY_EVT_BMP180 0x02
+
+#define SCL_PIN GPIO_ID_PIN((0))
+#define SDA_PIN GPIO_ID_PIN((2))
+
+typedef struct
+{
+    uint8_t event_type;
+    bmp180_result_t bmp180_data;
+} my_event_t;
+
+// Communication Queue
+static xQueueHandle mainqueue;
+static xTimerHandle timerHandle;
+
+// Own BMP180 User Inform Implementation
+bool bmp180_i2c_informUser(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure)
+{
+    my_event_t ev;
+
+    ev.event_type = MY_EVT_BMP180;
+    ev.bmp180_data.cmd = cmd;
+    ev.bmp180_data.temperatue = temperatue;
+    ev.bmp180_data.pressure = pressure;
+
+    return (xQueueSend(*resultQueue, &ev, 0) == pdTRUE);
+}
+
+// Timer call back
+static void bmp180_i2c_timer_cb(xTimerHandle xTimer)
+{
+    my_event_t ev;
+    ev.event_type = MY_EVT_TIMER;
+
+    xQueueSend(mainqueue, &ev, 0);
+}
+
+// Check for communiction events
+void bmp180_task(void *pvParameters)
+{
+    // Received pvParameters is communication queue
+    xQueueHandle *com_queue = (xQueueHandle *)pvParameters;
+
+    printf("%s: Started user interface task\n", __FUNCTION__);
+
+    while(1)
+    {
+        my_event_t ev;
+
+        xQueueReceive(*com_queue, &ev, portMAX_DELAY);
+
+        switch(ev.event_type)
+        {
+        case MY_EVT_TIMER:
+            printf("%s: Received Timer Event\n", __FUNCTION__);
+
+            bmp180_trigger_measurement(com_queue);
+            break;
+        case MY_EVT_BMP180:
+            printf("%s: Received BMP180 Event temp:=%ld.%d°C press=%ld.%02ldhPa\n", __FUNCTION__, \
+                       (int32_t)ev.bmp180_data.temperatue, abs((int32_t)(ev.bmp180_data.temperatue*10)%10), \
+                       ev.bmp180_data.pressure/100, ev.bmp180_data.pressure%100 );
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+// Setup HW
+void user_setup(void)
+{
+    // Set UART Parameter
+    sdk_uart_div_modify(0, UART_CLK_FREQ / 115200);
+
+    // Give the UART some time to settle
+    sdk_os_delay_us(500);
+}
+
+void user_init(void)
+{
+    // Setup HW
+    user_setup();
+
+    // Just some infomations
+    printf("\n");
+    printf("SDK version : %s\n", sdk_system_get_sdk_version());
+    printf("GIT version : %s\n", GITSHORTREV);
+
+    // Use our user inform implementation
+    bmp180_informUser = bmp180_i2c_informUser;
+
+    // Init BMP180 Interface
+    bmp180_init(SCL_PIN, SDA_PIN);
+
+    // Create Main Communication Queue
+    mainqueue = xQueueCreate(10, sizeof(my_event_t));
+
+    // Create user interface task
+    xTaskCreate(bmp180_task, (signed char *)"bmp180_task", 256, &mainqueue, 2, NULL);
+
+    // Create Timer (Trigger a measurement every second)
+    timerHandle = xTimerCreate((signed char *)"BMP180 Trigger", 1000/portTICK_RATE_MS, pdTRUE, NULL, bmp180_i2c_timer_cb);
+
+    if (timerHandle != NULL)
+    {
+        if (xTimerStart(timerHandle, 0) != pdPASS)
+        {
+            printf("%s: Unable to start Timer ...\n", __FUNCTION__);
+        }
+    }
+    else
+    {
+        printf("%s: Unable to create Timer ...\n", __FUNCTION__);
+    }
+}
diff --git a/extras/README.md b/extras/README.md
new file mode 100644
index 0000000..1bc0a52
--- /dev/null
+++ b/extras/README.md
@@ -0,0 +1,10 @@
+# extras
+
+This folder contains supportive source code.
+
+For current versions or reporting issues etc. please check the main development pages.
+
+- [bmp180](https://github.com/Angus71/esp-open-rtos-driver-bmp180)
+- [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c)
+- [rboot-ota](http://richard.burtons.org/)
+
diff --git a/extras/bmp180/LICENSE b/extras/bmp180/LICENSE
new file mode 100644
index 0000000..1f44f09
--- /dev/null
+++ b/extras/bmp180/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Frank Bargstedt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/extras/bmp180/README.md b/extras/bmp180/README.md
new file mode 100644
index 0000000..d6073c6
--- /dev/null
+++ b/extras/bmp180/README.md
@@ -0,0 +1,56 @@
+# Driver for BMP085/BMP180 digital pressure sensor
+
+This driver is written for usage with the ESP8266 and FreeRTOS ([esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos) and [esp-open-rtos-driver-i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c)).
+
+### Usage
+
+Before using the BMP180 module, the function `bmp180_init(SCL_PIN, SDA_PIN)` needs to be called to setup the I2C interface and do validation if the BMP180/BMP085 is accessible.
+
+If the setup is sucessfully and a measurement is triggered, the result of the measurement is provided to the user as an event send via the `qQueue` provided with `bmp180_trigger_*measurement(pQueue);` 
+
+#### Example 
+
+```
+#define SCL_PIN GPIO_ID_PIN(0)
+#define SDA_PIN GPIO_ID_PIN(2)
+...
+
+if (!bmp180_init(SCL_PIN, SDA_PIN)) {
+// An error occured, while dong the init (E.g device not found etc.)
+}
+
+// Trigger a measurement
+bmp180_trigger_measurement(pQueue);
+
+```
+
+#### Change queue event
+
+Per default the event send to the user via the provided queue is of the type `bmp180_result_t`. As this might not always be desired, a way is provided so that the user can provide a function, which creates and sends the event via the provided queue.
+
+As all data aqquired from the BMP180/BMP085 is provided to the `bmp180_informUser` function, it is also possible to calculate new informations (E.g altitude etc.)
+
+##### Example
+
+```
+// Own BMP180 User Inform Implementation
+bool my_informUser(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure) {
+	my_event_t ev;
+
+	ev.event_type = MY_EVT_BMP180;
+	ev.bmp180_data.cmd = cmd;
+	ev.bmp180_data.temperatue = temperatue;
+	ev.bmp180_data.pressure = pressure;
+
+	return (xQueueSend(*resultQueue, &ev, 0) == pdTRUE);
+}
+
+...
+
+// Use our user inform implementation
+// needs to be set before first measurement is triggered
+bmp180_informUser = my_informUser;
+
+
+``` 
+
diff --git a/extras/bmp180/bmp180.c b/extras/bmp180/bmp180.c
new file mode 100644
index 0000000..66203b0
--- /dev/null
+++ b/extras/bmp180/bmp180.c
@@ -0,0 +1,351 @@
+#include "bmp180.h"
+
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+#include "espressif/esp_common.h"
+#include "espressif/sdk_private.h"
+
+#include "i2c/i2c.h"
+
+#define BMP180_RX_QUEUE_SIZE      10
+#define BMP180_TASK_PRIORITY      9
+
+#define BMP180_DEVICE_ADDRESS     0x77
+
+#define BMP180_VERSION_REG        0xD0
+#define BMP180_CONTROL_REG        0xF4
+#define BMP180_RESET_REG          0xE0
+#define BMP180_OUT_MSB_REG        0xF6
+#define BMP180_OUT_LSB_REG        0xF7
+#define BMP180_OUT_XLSB_REG       0xF8
+
+#define BMP180_CALIBRATION_REG    0xAA
+
+//
+// Values for BMP180_CONTROL_REG
+//
+#define BMP180_MEASURE_TEMP       0x2E
+#define BMP180_MEASURE_PRESS_OSS0 0x34
+#define BMP180_MEASURE_PRESS_OSS1 0x74
+#define BMP180_MEASURE_PRESS_OSS2 0xB4
+#define BMP180_MEASURE_PRESS_OSS3 0xF4
+
+#define BMP180_DEFAULT_CONV_TIME  5000
+
+//
+// CHIP ID stored in BMP180_VERSION_REG
+//
+#define BMP180_CHIP_ID            0x55
+
+//
+// Reset value for BMP180_RESET_REG
+//
+#define BMP180_RESET_VALUE        0xB6
+
+
+// BMP180_Event_Command
+typedef struct
+{
+    uint8_t cmd;
+    const xQueueHandle* resultQueue;
+} bmp180_command_t;
+
+// Just works due to the fact that xQueueHandle is a "void *"
+static xQueueHandle bmp180_rx_queue = NULL;
+static xTaskHandle  bmp180_task_handle = NULL;
+
+// Calibration constants
+static int16_t  AC1;
+static int16_t  AC2;
+static int16_t  AC3;
+static uint16_t AC4;
+static uint16_t AC5;
+static uint16_t AC6;
+
+static int16_t  B1;
+static int16_t  B2;
+
+static int16_t  MB;
+static int16_t  MC;
+static int16_t  MD;
+
+//
+// Forward declarations
+//
+static void bmp180_meassure(const bmp180_command_t* command);
+static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure);
+
+// Set default implementation .. User gets result as bmp180_result_t event
+bool (*bmp180_informUser)(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure) = bmp180_informUser_Impl;
+
+// I2C Driver Task
+static void bmp180_driver_task(void *pvParameters)
+{
+    // Data to be received from user
+    bmp180_command_t current_command;
+
+#ifdef BMP180_DEBUG
+    // Wait for commands from the outside
+    printf("%s: Started Task\n", __FUNCTION__);
+#endif
+
+    while(1)
+    {
+        // Wait for user to insert commands
+        if (xQueueReceive(bmp180_rx_queue, &current_command, portMAX_DELAY) == pdTRUE)
+        {
+#ifdef BMP180_DEBUG
+            printf("%s: Received user command %d 0x%p\n", __FUNCTION__, current_command.cmd, current_command.resultQueue);
+#endif
+            // use user provided queue
+            if (current_command.resultQueue != NULL)
+            {
+                // Work on it ...
+                bmp180_meassure(&current_command);
+            }
+        }
+    }
+}
+
+static uint8_t bmp180_readRegister8(uint8_t reg)
+{
+    uint8_t r = 0;
+
+    if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, &r, 1))
+    {
+        r = 0;
+    }
+    return r;
+}
+
+
+static int16_t bmp180_readRegister16(uint8_t reg)
+{
+    uint8_t d[] = { 0, 0 };
+    int16_t r = 0;
+
+    if (i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, d, 2))
+    {
+        r = ((int16_t)d[0]<<8) | (d[1]);
+    }
+    return r;
+}
+
+static void bmp180_start_Messurement(uint8_t cmd)
+{
+    uint8_t d[] = { BMP180_CONTROL_REG, cmd };
+
+    i2c_slave_write(BMP180_DEVICE_ADDRESS, d, 2);
+}
+
+static int16_t bmp180_getUncompensatedMessurement(uint8_t cmd)
+{
+    // Write Start Code into reg 0xF4 (Currently without oversampling ...)
+    bmp180_start_Messurement((cmd==BMP180_TEMPERATURE)?BMP180_MEASURE_TEMP:BMP180_MEASURE_PRESS_OSS0);
+
+    // Wait 5ms Datasheet states 4.5ms
+    sdk_os_delay_us(BMP180_DEFAULT_CONV_TIME);
+
+    return (int16_t)bmp180_readRegister16(BMP180_OUT_MSB_REG);
+}
+
+static void bmp180_fillInternalConstants(void)
+{
+    AC1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+0);
+    AC2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+2);
+    AC3 = bmp180_readRegister16(BMP180_CALIBRATION_REG+4);
+    AC4 = bmp180_readRegister16(BMP180_CALIBRATION_REG+6);
+    AC5 = bmp180_readRegister16(BMP180_CALIBRATION_REG+8);
+    AC6 = bmp180_readRegister16(BMP180_CALIBRATION_REG+10);
+
+    B1 = bmp180_readRegister16(BMP180_CALIBRATION_REG+12);
+    B2 = bmp180_readRegister16(BMP180_CALIBRATION_REG+14);
+
+    MB = bmp180_readRegister16(BMP180_CALIBRATION_REG+16);
+    MC = bmp180_readRegister16(BMP180_CALIBRATION_REG+18);
+    MD = bmp180_readRegister16(BMP180_CALIBRATION_REG+20);
+
+#ifdef BMP180_DEBUG
+    printf("%s: AC1:=%d AC2:=%d AC3:=%d AC4:=%u AC5:=%u AC6:=%u \n", __FUNCTION__, AC1, AC2, AC3, AC4, AC5, AC6);
+    printf("%s: B1:=%d B2:=%d\n", __FUNCTION__, B1, B2);
+    printf("%s: MB:=%d MC:=%d MD:=%d\n", __FUNCTION__, MB, MC, MD);
+#endif
+}
+
+static bool bmp180_create_communication_queues()
+{
+    // Just create them once
+    if (bmp180_rx_queue==NULL)
+    {
+        bmp180_rx_queue = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t));
+    }
+
+    return (bmp180_rx_queue!=NULL);
+}
+
+static bool bmp180_is_avaialble()
+{
+    return (bmp180_readRegister8(BMP180_VERSION_REG)==BMP180_CHIP_ID);
+}
+
+static bool bmp180_createTask()
+{
+    // We already have a task
+    portBASE_TYPE x = pdPASS;
+
+    if (bmp180_task_handle==NULL)
+    {
+        x = xTaskCreate(bmp180_driver_task, (signed char *)"bmp180_driver_task", 256, NULL, BMP180_TASK_PRIORITY, &bmp180_task_handle);
+    }
+    return (x==pdPASS);
+}
+
+static void bmp180_meassure(const bmp180_command_t* command)
+{
+    int32_t T, P;
+
+    // Init result to 0
+    T = P = 0;
+
+    if (command->resultQueue != NULL)
+    {
+        int32_t UT, X1, X2, B5;
+
+        //
+        // Temperature is always needed ... Also required for pressure only
+        //
+        // Calculation taken from BMP180 Datasheet
+        UT = (int32_t)bmp180_getUncompensatedMessurement(BMP180_TEMPERATURE);
+
+        X1 = (UT - (int32_t)AC6) * ((int32_t)AC5) >> 15;
+        X2 = ((int32_t)MC << 11) / (X1 + (int32_t)MD);
+        B5 = X1 + X2;
+
+        T = (B5 + 8) >> 4;
+
+#ifdef BMP180_DEBUG
+        printf("%s: T:= %ld.%d\n", __FUNCTION__, T/10, abs(T%10));
+#endif
+
+        // Do we also need pressure?
+        if (command->cmd & BMP180_PRESSURE)
+        {
+            int32_t X3, B3, B6;
+            uint32_t B4, B7, UP;
+
+            UP = ((uint32_t)bmp180_getUncompensatedMessurement(BMP180_PRESSURE) & 0xFFFF);
+
+            // Calculation taken from BMP180 Datasheet
+            B6 = B5 - 4000;
+            X1 = ((int32_t)B2 * ((B6 * B6) >> 12)) >> 11;
+            X2 = ((int32_t)AC2 * B6) >> 11;
+            X3 = X1 + X2;
+
+            B3 = (((int32_t)AC1 * 4 + X3) + 2) >> 2;
+            X1 = ((int32_t)AC3 * B6) >> 13;
+            X2 = ((int32_t)B1 * ((B6 * B6) >> 12)) >> 16;
+            X3 = ((X1 + X2) + 2) >> 2;
+            B4 = ((uint32_t)AC4 * (uint32_t)(X3 + 32768)) >> 15;
+            B7 = (UP - B3) * (uint32_t)(50000UL);
+
+            if (B7 < 0x80000000)
+            {
+                P = (B7 * 2) / B4;
+            }
+            else
+            {
+                P = (B7 / B4) * 2;
+            }
+
+            X1 = (P >> 8) * (P >> 8);
+            X1 = (X1 * 3038) >> 16;
+            X2 = (-7357 * P) >> 16;
+            P = P + ((X1 + X2 + (int32_t)3791) >> 4);
+
+#ifdef BMP180_DEBUG
+            printf("%s: P:= %ld\n", __FUNCTION__, P);
+#endif
+        }
+
+        // Inform the user ...
+        if (!bmp180_informUser(command->resultQueue, command->cmd, ((bmp180_temp_t)T)/10.0, (bmp180_press_t)P))
+        {
+            // Failed to send info to user
+            printf("%s: Unable to inform user bmp180_informUser returned \"false\"\n", __FUNCTION__);
+        }
+    }
+}
+
+// Default user inform implementation
+static bool bmp180_informUser_Impl(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure)
+{
+    bmp180_result_t result;
+
+    result.cmd = cmd;
+    result.temperatue = temperatue;
+    result.pressure = pressure;
+
+    return (xQueueSend(*resultQueue, &result, 0) == pdTRUE);
+}
+
+// Just init all needed queues
+bool bmp180_init(uint8_t scl, uint8_t sda)
+{
+    // 1. Create required queues
+    bool result = false;
+
+    if (bmp180_create_communication_queues())
+    {
+        // 2. Init i2c driver
+        i2c_init(scl, sda);
+
+        // 3. Check for bmp180 ...
+        if (bmp180_is_avaialble())
+        {
+            // 4. Init all internal constants ...
+            bmp180_fillInternalConstants();
+
+            // 5. Start driver task
+            if (bmp180_createTask())
+            {
+                // We are finished
+                result = true;
+            }
+        }
+    }
+
+    return result;
+}
+
+void bmp180_trigger_measurement(const xQueueHandle* resultQueue)
+{
+    bmp180_command_t c;
+
+    c.cmd = BMP180_PRESSURE + BMP180_TEMPERATURE;
+    c.resultQueue = resultQueue;
+
+    xQueueSend(bmp180_rx_queue, &c, 0);
+}
+
+
+void bmp180_trigger_pressure_measurement(const xQueueHandle* resultQueue)
+{
+    bmp180_command_t c;
+
+    c.cmd = BMP180_PRESSURE;
+    c.resultQueue = resultQueue;
+
+    xQueueSend(bmp180_rx_queue, &c, 0);
+}
+
+void bmp180_trigger_temperature_measurement(const xQueueHandle* resultQueue)
+{
+    bmp180_command_t c;
+
+    c.cmd = BMP180_TEMPERATURE;
+    c.resultQueue = resultQueue;
+
+    xQueueSend(bmp180_rx_queue, &c, 0);
+}
diff --git a/extras/bmp180/bmp180.h b/extras/bmp180/bmp180.h
new file mode 100644
index 0000000..73709ff
--- /dev/null
+++ b/extras/bmp180/bmp180.h
@@ -0,0 +1,55 @@
+/*
+ * bmp180.h
+ *
+ *  Created on: 23.08.2015
+ *      Author: fbargste
+ */
+
+#ifndef DRIVER_BMP180_H_
+#define DRIVER_BMP180_H_
+
+#include "stdint.h"
+#include "stdbool.h"
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+// Uncomment to enable debug output
+//#define BMP180_DEBUG
+
+#define BMP180_TEMPERATURE (1<<0)
+#define BMP180_PRESSURE    (1<<1)
+
+//
+// Create bmp180_types
+//
+
+// temperature in °C
+typedef float bmp180_temp_t;
+// pressure in mPa (To get hPa divide by 100)
+typedef uint32_t bmp180_press_t;
+
+// BMP180_Event_Result
+typedef struct
+{
+    uint8_t cmd;
+    bmp180_temp_t  temperatue;
+    bmp180_press_t pressure;
+} bmp180_result_t;
+
+// Init bmp180 driver ...
+bool bmp180_init(uint8_t scl, uint8_t sda);
+
+// Trigger a "complete" measurement (temperature and pressure will be valid when given to "bmp180_informUser)
+void bmp180_trigger_measurement(const xQueueHandle* resultQueue);
+
+// Trigger a "temperature only" measurement (only temperature will be valid when given to "bmp180_informUser)
+void bmp180_trigger_temperature_measurement(const xQueueHandle* resultQueue);
+
+// Trigger a "pressure only" measurement (only pressure will be valid when given to "bmp180_informUser)
+void bmp180_trigger_pressure_measurement(const xQueueHandle* resultQueue);
+
+// Give the user the chance to create it's own handler
+extern bool (*bmp180_informUser)(const xQueueHandle* resultQueue, uint8_t cmd, bmp180_temp_t temperatue, bmp180_press_t pressure);
+
+#endif /* DRIVER_BMP180_H_ */
diff --git a/extras/bmp180/component.mk b/extras/bmp180/component.mk
new file mode 100644
index 0000000..5efc68a
--- /dev/null
+++ b/extras/bmp180/component.mk
@@ -0,0 +1,9 @@
+# Component makefile for extras/bmp180
+
+INC_DIRS += $(ROOT)extras
+
+# args for passing into compile rule generation
+extras/bmp180_INC_DIR =  $(ROOT)extras
+extras/bmp180_SRC_DIR =  $(ROOT)extras/bmp180
+
+$(eval $(call component_compile_rules,extras/bmp180))
diff --git a/extras/i2c/LICENSE b/extras/i2c/LICENSE
new file mode 100644
index 0000000..85820f6
--- /dev/null
+++ b/extras/i2c/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Johan Kanflo
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/extras/i2c/README.md b/extras/i2c/README.md
new file mode 100644
index 0000000..7ab90f6
--- /dev/null
+++ b/extras/i2c/README.md
@@ -0,0 +1,40 @@
+# Yet another I2C driver for the ESP8266
+
+This time a driver for the excellent esp-open-rtos. This is a bit banging I2C driver based on the Wikipedia pesudo C code [1].
+
+### Adding to your project
+
+Add the driver to your project as a submodule rather than cloning it:
+
+````
+% git submodule add https://github.com/kanflo/esp-open-rtos-driver-i2c.git i2c
+````
+The esp-open-rtos makefile-fu will make sure the driver is built.
+
+### Usage
+
+
+````
+#include <i2c.h>
+
+#define SCL_PIN (0)
+#define SDA_PIN (2)
+
+uint8_t slave_addr = 0x20;
+uint8_t reg_addr = 0x1f;
+uint8_t reg_data;
+uint8_t data[] = {reg_addr, 0xc8};
+
+i2c_init(SCL_PIN, SDA_PIN);
+
+// Write data to slave
+bool success = i2c_slave_write(slave_addr, data, sizeof(data));
+
+// Issue write to slave, sending reg_addr, followed by reading 1 byte
+success = i2c_slave_read(slave_addr, &reg_addr, reg_data, 1);
+
+````
+
+The driver is released under the MIT license.
+
+[1] https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
\ No newline at end of file
diff --git a/extras/i2c/component.mk b/extras/i2c/component.mk
new file mode 100644
index 0000000..13b0f83
--- /dev/null
+++ b/extras/i2c/component.mk
@@ -0,0 +1,9 @@
+# Component makefile for extras/i2c
+
+INC_DIRS += $(ROOT)extras
+
+# args for passing into compile rule generation
+extras/i2c_INC_DIR =  $(ROOT)extras
+extras/i2c_SRC_DIR =  $(ROOT)extras/i2c
+
+$(eval $(call component_compile_rules,extras/i2c))
diff --git a/extras/i2c/i2c.c b/extras/i2c/i2c.c
new file mode 100644
index 0000000..ef19c45
--- /dev/null
+++ b/extras/i2c/i2c.c
@@ -0,0 +1,229 @@
+/* 
+ * The MIT License (MIT)
+ * 
+ * Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <esp8266.h>
+#include <espressif/esp_misc.h> // sdk_os_delay_us
+#include "i2c.h"
+
+
+// I2C driver for ESP8266 written for use with esp-open-rtos
+// Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
+
+// With calling overhead, we end up at ~100kbit/s
+#define CLK_HALF_PERIOD_US (1)
+
+#define CLK_STRETCH  (10)
+
+static bool started;
+static uint8_t g_scl_pin;
+static uint8_t g_sda_pin;
+
+void i2c_init(uint8_t scl_pin, uint8_t sda_pin)
+{
+    started = false;
+    g_scl_pin = scl_pin;
+    g_sda_pin = sda_pin;
+}
+
+static void i2c_delay(void)
+{
+    sdk_os_delay_us(CLK_HALF_PERIOD_US);
+}
+
+// Set SCL as input and return current level of line, 0 or 1
+static bool read_scl(void)
+{
+    gpio_enable(g_scl_pin, GPIO_INPUT);
+    return gpio_read(g_scl_pin); // Clock high, valid ACK
+}
+
+// Set SDA as input and return current level of line, 0 or 1
+static bool read_sda(void)
+{
+    gpio_enable(g_sda_pin, GPIO_INPUT);
+    // TODO: Without this delay we get arbitration lost in i2c_stop
+    i2c_delay();
+    return gpio_read(g_sda_pin); // Clock high, valid ACK
+}
+
+// Actively drive SCL signal low
+static void clear_scl(void)
+{
+    gpio_enable(g_scl_pin, GPIO_OUTPUT);
+    gpio_write(g_scl_pin, 0);
+}
+
+// Actively drive SDA signal low
+static void clear_sda(void)
+{
+    gpio_enable(g_sda_pin, GPIO_OUTPUT);
+    gpio_write(g_sda_pin, 0);
+}
+
+// Output start condition
+void i2c_start(void)
+{
+    uint32_t clk_stretch = CLK_STRETCH;
+    if (started) { // if started, do a restart cond
+        // Set SDA to 1
+        (void) read_sda();
+        i2c_delay();
+        while (read_scl() == 0 && clk_stretch--) ;
+        // Repeated start setup time, minimum 4.7us
+        i2c_delay();
+    }
+    if (read_sda() == 0) {
+        printf("I2C: arbitration lost in i2c_start\n");
+    }
+    // SCL is high, set SDA from 1 to 0.
+    clear_sda();
+    i2c_delay();
+    clear_scl();
+    started = true;
+}
+
+// Output stop condition
+void i2c_stop(void)
+{
+    uint32_t clk_stretch = CLK_STRETCH;
+    // Set SDA to 0
+    clear_sda();
+    i2c_delay();
+    // Clock stretching
+    while (read_scl() == 0 && clk_stretch--) ;
+    // Stop bit setup time, minimum 4us
+    i2c_delay();
+    // SCL is high, set SDA from 0 to 1
+    if (read_sda() == 0) {
+        printf("I2C: arbitration lost in i2c_stop\n");
+    }
+    i2c_delay();
+    started = false;
+}
+
+// Write a bit to I2C bus
+static void i2c_write_bit(bool bit)
+{
+    uint32_t clk_stretch = CLK_STRETCH;
+    if (bit) {
+        (void) read_sda();
+    } else {
+        clear_sda();
+    }
+    i2c_delay();
+    // Clock stretching
+    while (read_scl() == 0 && clk_stretch--) ;
+    // SCL is high, now data is valid
+    // If SDA is high, check that nobody else is driving SDA
+    if (bit && read_sda() == 0) {
+        printf("I2C: arbitration lost in i2c_write_bit\n");
+    }
+    i2c_delay();
+    clear_scl();
+}
+
+// Read a bit from I2C bus
+static bool i2c_read_bit(void)
+{
+    uint32_t clk_stretch = CLK_STRETCH;
+    bool bit;
+    // Let the slave drive data
+    (void) read_sda();
+    i2c_delay();
+    // Clock stretching
+    while (read_scl() == 0 && clk_stretch--) ;
+    // SCL is high, now data is valid
+    bit = read_sda();
+    i2c_delay();
+    clear_scl();
+    return bit;
+}
+
+bool i2c_write(uint8_t byte)
+{
+    bool nack;
+    uint8_t bit;
+    for (bit = 0; bit < 8; bit++) {
+        i2c_write_bit((byte & 0x80) != 0);
+        byte <<= 1;
+    }
+    nack = i2c_read_bit();
+    return !nack;
+}
+
+uint8_t i2c_read(bool ack)
+{
+    uint8_t byte = 0;
+    uint8_t bit;
+    for (bit = 0; bit < 8; bit++) {
+        byte = (byte << 1) | i2c_read_bit();
+    }
+    i2c_write_bit(ack);
+    return byte;
+}
+
+bool i2c_slave_write(uint8_t slave_addr, uint8_t *data, uint8_t len)
+{
+    bool success = false;
+    do {
+        i2c_start();
+        if (!i2c_write(slave_addr << 1))
+            break;
+        while (len--) {
+            if (!i2c_write(*data++))
+                break;
+        }
+        i2c_stop();
+        success = true;
+    } while(0);
+    return success;
+}
+
+bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len)
+{
+    bool success = false;
+    do {
+        i2c_start();
+        if (!i2c_write(slave_addr << 1)) {
+            break;
+        }
+        i2c_write(data);
+        i2c_stop();
+        i2c_start();
+        if (!i2c_write(slave_addr << 1 | 1)) { // Slave address + read
+            break;
+        }
+        while(len) {
+            *buf = i2c_read(len == 1);
+            buf++;
+            len--;
+        }
+        success = true;
+    } while(0);
+    i2c_stop();
+    if (!success) {
+        printf("I2C: write error\n");
+    }
+    return success;
+}
diff --git a/extras/i2c/i2c.h b/extras/i2c/i2c.h
new file mode 100644
index 0000000..ac3163f
--- /dev/null
+++ b/extras/i2c/i2c.h
@@ -0,0 +1,51 @@
+/* 
+ * The MIT License (MIT)
+ * 
+ * Copyright (c) 2015 Johan Kanflo (github.com/kanflo)
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef __I2C_H__
+#define __I2C_H__
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+
+// Init bitbanging I2C driver on given pins
+void i2c_init(uint8_t scl_pin, uint8_t sda_pin);
+
+// Write a byte to I2C bus. Return true if slave acked.
+bool i2c_write(uint8_t byte);
+
+// Read a byte from I2C bus. Return true if slave acked.
+uint8_t i2c_read(bool ack);
+
+// Write 'len' bytes from 'buf' to slave. Return true if slave acked.
+bool i2c_slave_write(uint8_t slave_addr, uint8_t *buf, uint8_t len);
+
+// Issue a read operation and send 'data', followed by reading 'len' bytes
+// from slave into 'buf'. Return true if slave acked.
+bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len);
+
+// Send start and stop conditions. Only needed when implementing protocols for
+// devices where the i2c_slave_[read|write] functions above are of no use.
+void i2c_start(void);
+void i2c_stop(void);