diff --git a/cores/esp8266/HardwareSerial.cpp b/cores/esp8266/HardwareSerial.cpp
index b69729ae4..979b0c0da 100644
--- a/cores/esp8266/HardwareSerial.cpp
+++ b/cores/esp8266/HardwareSerial.cpp
@@ -32,21 +32,13 @@
 
 
 HardwareSerial::HardwareSerial(int uart_nr)
-    : _uart_nr(uart_nr)
+    : _uart_nr(uart_nr), _rx_size(256)
 {}
 
 void HardwareSerial::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin)
 {
-    if(uart_get_debug() == _uart_nr) {
-        uart_set_debug(UART_NO);
-    }
-
-    if (_uart) {
-        free(_uart);
-    }
-
-    _uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin);
-    _peek_char = -1;
+    end();
+    _uart = uart_init(_uart_nr, baud, (int) config, (int) mode, tx_pin, _rx_size);
 }
 
 void HardwareSerial::end()
@@ -55,8 +47,19 @@ void HardwareSerial::end()
         uart_set_debug(UART_NO);
     }
 
-    uart_uninit(_uart);
-    _uart = NULL;
+    if (_uart) {
+        uart_uninit(_uart);
+        _uart = NULL;
+    }
+}
+
+size_t HardwareSerial::setRxBufferSize(size_t size){
+    if(_uart) {
+        _rx_size = uart_resize_rx_buffer(_uart, size);
+    } else {
+        _rx_size = size;
+    }
+    return _rx_size;
 }
 
 void HardwareSerial::swap(uint8_t tx_pin)
@@ -114,14 +117,7 @@ bool HardwareSerial::isRxEnabled(void)
 
 int HardwareSerial::available(void)
 {
-    if(!_uart || !uart_rx_enabled(_uart)) {
-        return 0;
-    }
-
     int result = static_cast<int>(uart_rx_available(_uart));
-    if (_peek_char != -1) {
-        result += 1;
-    }
     if (!result) {
         optimistic_yield(10000);
     }
@@ -130,25 +126,13 @@ int HardwareSerial::available(void)
 
 int HardwareSerial::peek(void)
 {
-    if (_peek_char != -1) {
-        return _peek_char;
-    }
     // this may return -1, but that's okay
-    _peek_char = uart_read_char(_uart);
-    return _peek_char;
+    return uart_peek_char(_uart);
 }
 
 int HardwareSerial::read(void)
 {
-    if(!_uart || !uart_rx_enabled(_uart)) {
-        return -1;
-    }
-
-    if (_peek_char != -1) {
-        auto tmp = _peek_char;
-        _peek_char = -1;
-        return tmp;
-    }
+    // this may return -1, but that's okay
     return uart_read_char(_uart);
 }
 
diff --git a/cores/esp8266/HardwareSerial.h b/cores/esp8266/HardwareSerial.h
index a05cb5d30..4b384fee5 100644
--- a/cores/esp8266/HardwareSerial.h
+++ b/cores/esp8266/HardwareSerial.h
@@ -87,6 +87,8 @@ public:
 
     void end();
 
+    size_t setRxBufferSize(size_t size);
+
     void swap()
     {
         swap(1);
@@ -138,7 +140,7 @@ public:
 protected:
     int _uart_nr;
     uart_t* _uart = nullptr;
-    int _peek_char = -1;
+    size_t _rx_size;
 };
 
 extern HardwareSerial Serial;
diff --git a/cores/esp8266/uart.c b/cores/esp8266/uart.c
index 123261aef..9f0f0eb1b 100644
--- a/cores/esp8266/uart.c
+++ b/cores/esp8266/uart.c
@@ -47,6 +47,13 @@
 
 static int s_uart_debug_nr = UART0;
 
+struct uart_rx_buffer_ {
+    size_t size;
+    size_t rpos;
+    size_t wpos;
+    uint8_t * buffer;
+};
+
 struct uart_ {
     int uart_nr;
     int baud_rate;
@@ -54,8 +61,132 @@ struct uart_ {
     bool tx_enabled;
     uint8_t rx_pin;
     uint8_t tx_pin;
+    struct uart_rx_buffer_ * rx_buffer;
 };
 
+size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size)
+{
+    if(uart == NULL || !uart->rx_enabled) {
+        return 0;
+    }
+    if(uart->rx_buffer->size == new_size) {
+        return uart->rx_buffer->size;
+    }
+    uint8_t * new_buf = (uint8_t*)malloc(new_size);
+    if(!new_buf) {
+        return uart->rx_buffer->size;
+    }
+    size_t new_wpos = 0;
+    ETS_UART_INTR_DISABLE();
+    while(uart_rx_available(uart) && new_wpos < new_size) {
+        new_buf[new_wpos++] = uart_read_char(uart);
+    }
+    uint8_t * old_buf = uart->rx_buffer->buffer;
+    uart->rx_buffer->rpos = 0;
+    uart->rx_buffer->wpos = new_wpos;
+    uart->rx_buffer->size = new_size;
+    uart->rx_buffer->buffer = new_buf;
+    free(old_buf);
+    ETS_UART_INTR_ENABLE();
+    return uart->rx_buffer->size;
+}
+
+int uart_peek_char(uart_t* uart)
+{
+    if(uart == NULL || !uart->rx_enabled) {
+        return -1;
+    }
+    if (!uart_rx_available(uart)) {
+        return -1;
+    }
+    return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
+}
+
+int uart_read_char(uart_t* uart)
+{
+    int data = uart_peek_char(uart);
+    if(data != -1) {
+        uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
+    }
+    return data;
+}
+
+size_t uart_rx_available(uart_t* uart)
+{
+    if(uart == NULL || !uart->rx_enabled) {
+        return 0;
+    }
+    if(uart->rx_buffer->wpos < uart->rx_buffer->rpos) {
+      return (uart->rx_buffer->wpos + uart->rx_buffer->size) - uart->rx_buffer->rpos;
+    }
+    return uart->rx_buffer->wpos - uart->rx_buffer->rpos;
+}
+
+
+void ICACHE_RAM_ATTR uart_isr(void * arg)
+{
+    uart_t* uart = (uart_t*)arg;
+    if(uart == NULL || !uart->rx_enabled) {
+        USIC(uart->uart_nr) = 0xffff;
+        ETS_UART_INTR_DISABLE();
+        return;
+    }
+
+    uint32_t int_status = USIS(uart->uart_nr);
+
+    if(int_status & (1 << UIFR)) {
+        USIC(uart->uart_nr) = (1 << UIFR);//clear any frame error
+    }
+
+    if(int_status & (1 << UIFF) || int_status & (1 << UITO)){
+        ETS_UART_INTR_DISABLE();
+        while(((USS(uart->uart_nr) >> USRXC) & 0x7F) != 0){
+            uint8_t data = USF(uart->uart_nr);
+            size_t nextPos = (uart->rx_buffer->wpos + 1) % uart->rx_buffer->size;
+            if(nextPos != uart->rx_buffer->rpos) {
+                uart->rx_buffer->buffer[uart->rx_buffer->wpos] = data;
+                uart->rx_buffer->wpos = nextPos;
+            } else {
+                //rx buffer OverFlow
+                //maybe stop the loop and try later?
+            }
+        }
+        int_status = USIS(uart->uart_nr);
+        if(int_status & (1 << UIFF)) {
+            USIC(uart->uart_nr) = (1 << UIFF);//clear any FIFO FULL error
+        }
+        if(int_status & (1 << UITO)) {
+            USIC(uart->uart_nr) = (1 << UITO);//clear any TimeOut error
+        }
+        ETS_UART_INTR_ENABLE();
+    }
+}
+
+void uart_start_isr(uart_t* uart)
+{
+    if(uart == NULL || !uart->rx_enabled) {
+        return;
+    }
+    USC1(uart->uart_nr) = (127 << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
+    USIC(uart->uart_nr) = 0xffff;
+    USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
+    ETS_UART_INTR_ATTACH(uart_isr,  (void *)uart);
+    ETS_UART_INTR_ENABLE();
+}
+
+void uart_stop_isr(uart_t* uart)
+{
+    if(uart == NULL || !uart->rx_enabled) {
+        return;
+    }
+    ETS_UART_INTR_DISABLE();
+    USC1(uart->uart_nr) = 0;
+    USIC(uart->uart_nr) = 0xffff;
+    USIE(uart->uart_nr) = 0;
+    ETS_UART_INTR_ATTACH(NULL, NULL);
+}
+
+
 void uart_write_char(uart_t* uart, char c)
 {
     if(uart == NULL || !uart->tx_enabled) {
@@ -75,25 +206,6 @@ void uart_write(uart_t* uart, const char* buf, size_t size)
     }
 }
 
-int uart_read_char(uart_t* uart)
-{
-    if(uart == NULL || !uart->rx_enabled) {
-        return -1;
-    }
-    if (!uart_rx_available(uart)) {
-        return -1;
-    }
-    return USF(uart->uart_nr) & 0xff;
-}
-
-size_t uart_rx_available(uart_t* uart)
-{
-    if(uart == NULL || !uart->rx_enabled) {
-        return -1;
-    }
-    return (USS(uart->uart_nr) >> USRXC) & 0xff;
-}
-
 size_t uart_tx_free(uart_t* uart)
 {
     if(uart == NULL || !uart->tx_enabled) {
@@ -121,6 +233,10 @@ void uart_flush(uart_t* uart)
     uint32_t tmp = 0x00000000;
     if(uart->rx_enabled) {
         tmp |= (1 << UCRXRST);
+        ETS_UART_INTR_DISABLE();
+        uart->rx_buffer->rpos = 0;
+        uart->rx_buffer->wpos = 0;
+        ETS_UART_INTR_ENABLE();
     }
 
     if(uart->tx_enabled) {
@@ -148,7 +264,7 @@ int uart_get_baudrate(uart_t* uart)
     return uart->baud_rate;
 }
 
-uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
+uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size)
 {
     uart_t* uart = (uart_t*) malloc(sizeof(uart_t));
     if(uart == NULL) {
@@ -159,9 +275,29 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
 
     switch(uart->uart_nr) {
     case UART0:
+        ETS_UART_INTR_DISABLE();
+        ETS_UART_INTR_ATTACH(NULL, NULL);
         uart->rx_enabled = (mode != UART_TX_ONLY);
         uart->tx_enabled = (mode != UART_RX_ONLY);
         uart->rx_pin = (uart->rx_enabled)?3:255;
+        if(uart->rx_enabled) {
+            struct uart_rx_buffer_ * rx_buffer = (struct uart_rx_buffer_ *)malloc(sizeof(struct uart_rx_buffer_));
+            if(rx_buffer == NULL) {
+              free(uart);
+              return NULL;
+            }
+            rx_buffer->size = rx_size;//var this
+            rx_buffer->rpos = 0;
+            rx_buffer->wpos = 0;
+            rx_buffer->buffer = (uint8_t *)malloc(rx_buffer->size);
+            if(rx_buffer->buffer == NULL) {
+              free(rx_buffer);
+              free(uart);
+              return NULL;
+            }
+            uart->rx_buffer = rx_buffer;
+            pinMode(uart->rx_pin, SPECIAL);
+        }
         if(uart->tx_enabled) {
             if (tx_pin == 2) {
                 uart->tx_pin = 2;
@@ -173,9 +309,6 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
         } else {
             uart->tx_pin = 255;
         }
-        if(uart->rx_enabled) {
-            pinMode(uart->rx_pin, SPECIAL);
-        }
         IOSWAP &= ~(1 << IOSWAPU0);
         break;
     case UART1:
@@ -199,6 +332,11 @@ uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin)
     USC0(uart->uart_nr) = config;
     uart_flush(uart);
     USC1(uart->uart_nr) = 0;
+    USIC(uart->uart_nr) = 0xffff;
+    USIE(uart->uart_nr) = 0;
+    if(uart->uart_nr == UART0 && uart->rx_enabled) {
+        uart_start_isr(uart);
+    }
 
     return uart;
 }
@@ -230,6 +368,11 @@ void uart_uninit(uart_t* uart)
         break;
     }
 
+    if(uart->rx_enabled){
+        free(uart->rx_buffer->buffer);
+        free(uart->rx_buffer);
+        //uart_stop_isr(uart);
+    }
     free(uart);
 }
 
diff --git a/cores/esp8266/uart.h b/cores/esp8266/uart.h
index e5480f222..b79745adf 100644
--- a/cores/esp8266/uart.h
+++ b/cores/esp8266/uart.h
@@ -113,7 +113,7 @@ extern "C" {
 struct uart_;
 typedef struct uart_ uart_t;
 
-uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin);
+uart_t* uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx_size);
 void uart_uninit(uart_t* uart);
 
 void uart_swap(uart_t* uart, int tx_pin);
@@ -125,9 +125,12 @@ bool uart_rx_enabled(uart_t* uart);
 void uart_set_baudrate(uart_t* uart, int baud_rate);
 int uart_get_baudrate(uart_t* uart);
 
+size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size);
+
 void uart_write_char(uart_t* uart, char c);
 void uart_write(uart_t* uart, const char* buf, size_t size);
 int uart_read_char(uart_t* uart);
+int uart_peek_char(uart_t* uart);
 size_t uart_rx_available(uart_t* uart);
 size_t uart_tx_free(uart_t* uart);
 void uart_wait_tx_empty(uart_t* uart);