jeong chanmi / BlynkNeopixelW7500

Fork of WIZwiki-7500_Blynk by IOP

Files at this revision

API Documentation at this revision

Comitter:
vshymanskyy
Date:
Sat May 07 08:02:50 2016 +0000
Child:
1:401940b68eae
Commit message:
First commit

Changed in this revision

Blynk/BlynkApi.h Show annotated file Show diff for this revision Revisions of this file
Blynk/BlynkConfig.h Show annotated file Show diff for this revision Revisions of this file
Blynk/BlynkDebug.h Show annotated file Show diff for this revision Revisions of this file
Blynk/BlynkDetectDevice.h Show annotated file Show diff for this revision Revisions of this file
Blynk/BlynkHandlers.h Show annotated file Show diff for this revision Revisions of this file
Blynk/BlynkParam.h Show annotated file Show diff for this revision Revisions of this file
Blynk/BlynkProtocol.h Show annotated file Show diff for this revision Revisions of this file
Blynk/BlynkProtocolDefs.h Show annotated file Show diff for this revision Revisions of this file
BlynkApiMbed.h Show annotated file Show diff for this revision Revisions of this file
BlynkSimpleUserDefined.h Show annotated file Show diff for this revision Revisions of this file
BlynkWidgets.h Show annotated file Show diff for this revision Revisions of this file
WidgetBridge.h Show annotated file Show diff for this revision Revisions of this file
WidgetLCD.h Show annotated file Show diff for this revision Revisions of this file
WidgetLED.h Show annotated file Show diff for this revision Revisions of this file
WidgetTerminal.h Show annotated file Show diff for this revision Revisions of this file
utility/BlynkDebug.cpp Show annotated file Show diff for this revision Revisions of this file
utility/BlynkFifo.h Show annotated file Show diff for this revision Revisions of this file
utility/BlynkFifo2.h Show annotated file Show diff for this revision Revisions of this file
utility/BlynkHandlers.cpp Show annotated file Show diff for this revision Revisions of this file
utility/BlynkUtility.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkApi.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,271 @@
+/**
+ * @file       BlynkApi.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      High-level functions
+ *
+ */
+
+#ifndef BlynkApi_h
+#define BlynkApi_h
+
+#include <Blynk/BlynkConfig.h>
+#include <Blynk/BlynkDebug.h>
+#include <Blynk/BlynkParam.h>
+#include <Blynk/BlynkHandlers.h>
+#include <Blynk/BlynkProtocolDefs.h>
+
+/**
+ * Represents high-level functions of Blynk
+ */
+template <class Proto>
+class BlynkApi
+{
+public:
+    BlynkApi() {
+        Init();
+    }
+
+#ifdef DOXYGEN // These API here are only for the documentation
+
+    /**
+     * Connects to the server.
+     * Blocks until connected or timeout happens.
+     * May take less or more then timeout value.
+     *
+     * @param timeout    Connection timeout
+     * @returns          True if connected to the server
+     */
+    bool connect(unsigned long timeout = BLYNK_TIMEOUT_MS*3);
+
+    /**
+     * Disconnects from the server.
+     * It will not try to reconnect, until connect() is called
+     */
+    void disconnect();
+
+    /**
+     * @returns          True if connected to the server
+     */
+    bool connected();
+
+    /**
+     * Performs Blynk-related housekeeping
+     * and processes incoming commands
+     *
+     * @param available  True if there is incoming data to process
+     *                   Only used when user manages connection manually.
+     */
+    bool run(bool available = false);
+
+#endif // DOXYGEN
+
+    /**
+     * Sends value to a Virtual Pin
+     *
+     * @param pin  Virtual Pin number
+     * @param data Value to be sent
+     */
+    template <typename T>
+    void virtualWrite(int pin, const T& data) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T1, typename T2>
+    void virtualWrite(int pin, const T1& data1, const T2& data2) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data1);
+        cmd.add(data2);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T1, typename T2, typename T3>
+    void virtualWrite(int pin, const T1& data1, const T2& data2, const T3& data3) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data1);
+        cmd.add(data2);
+        cmd.add(data3);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T1, typename T2, typename T3, typename T4>
+    void virtualWrite(int pin, const T1& data1, const T2& data2, const T3& data3, const T4& data4) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data1);
+        cmd.add(data2);
+        cmd.add(data3);
+        cmd.add(data4);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    /**
+     * Sends buffer to a Virtual Pin
+     *
+     * @param pin  Virtual Pin number
+     * @param buff Data buffer
+     * @param len  Length of data
+     */
+    void virtualWriteBinary(int pin, const void* buff, size_t len) {
+        char mem[8];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("vw");
+        cmd.add(pin);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength(), buff, len);
+    }
+
+    /**
+     * Sends BlynkParam to a Virtual Pin
+     *
+     * @param pin  Virtual Pin number
+     * @param param
+     */
+    void virtualWrite(int pin, const BlynkParam& param) {
+        virtualWriteBinary(pin, param.getBuffer(), param.getLength());
+    }
+
+    /**
+     * Requests Server to re-send current values for all widgets.
+     */
+    void syncAll() {
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE_SYNC);
+    }
+
+    /**
+     * Requests App or Server to re-send current value of a Virtual Pin.
+     * This will probably cause user-defined BLYNK_WRITE handler to be called.
+     *
+     * @param pin Virtual Pin number
+     */
+    void syncVirtual(int pin) {
+        char mem[8];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("vr");
+        cmd.add(pin);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE_SYNC, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    /**
+     * Tweets a message
+     *
+     * @param msg Text of the message
+     */
+    template<typename T>
+    void tweet(const T& msg) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(msg);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_TWEET, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    /**
+     * Sends a push notification to the App
+     *
+     * @param msg Text of the message
+     */
+    template<typename T>
+    void notify(const T& msg) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(msg);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_NOTIFY, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    /**
+     * Sends an SMS
+     *
+     * @param msg Text of the message
+     */
+    template<typename T>
+    void sms(const T& msg) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(msg);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_SMS, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    /**
+     * Sends an email message
+     *
+     * @param email   Email to send to
+     * @param subject Subject of message
+     * @param msg     Text of the message
+     */
+    template <typename T1, typename T2>
+    void email(const char* email, const T1& subject, const T2& msg) {
+        char mem[BLYNK_MAX_SENDBYTES];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(email);
+        cmd.add(subject);
+        cmd.add(msg);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_EMAIL, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+#if defined(BLYNK_EXPERIMENTAL)
+    // Attention!
+    // Every function in this section may be changed, removed or renamed.
+
+    /**
+     * Refreshes value of a widget by running
+     * user-defined BLYNK_READ handler of a pin.
+     *
+     * @experimental
+     *
+     * @param pin Virtual Pin number
+     */
+    void refresh(int pin) {
+        if (WidgetReadHandler handler = GetReadHandler(pin)) {
+            BlynkReq req = { 0, BLYNK_SUCCESS, (uint8_t)pin };
+            handler(req);
+        }
+    }
+
+    /**
+     * Delays for N milliseconds, handling server communication in background.
+     *
+     * @experimental
+     * @warning Should be used very carefully, especially on platforms with small RAM.
+     *
+     * @param ms Milliseconds to wait
+     */
+    void delay(unsigned long ms) {
+        uint16_t start = (uint16_t)micros();
+        while (ms > 0) {
+            static_cast<Proto*>(this)->run();
+#if !defined(BLYNK_NO_YIELD)
+            yield();
+#endif
+            if (((uint16_t)micros() - start) >= 1000) {
+                ms--;
+                start += 1000;
+            }
+        }
+    }
+
+#endif
+
+protected:
+    void Init();
+    static millis_time_t getMillis();
+    void processCmd(const void* buff, size_t len);
+    void sendInfo();
+
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkConfig.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,83 @@
+/**
+ * @file       BlynkConfig.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Configuration of different aspects of library
+ *
+ */
+
+#ifndef BlynkConfig_h
+#define BlynkConfig_h
+
+#include "Blynk/BlynkDetectDevice.h"
+
+/***************************************************
+ * Change these settings to match your need
+ ***************************************************/
+
+#define BLYNK_DEFAULT_DOMAIN     "blynk-cloud.com"
+#define BLYNK_DEFAULT_PORT       8442
+#define BLYNK_DEFAULT_PORT_SSL   8441
+
+/***************************************************
+ * Professional settings
+ ***************************************************/
+// Library version.
+#define BLYNK_VERSION        "0.3.5-beta"
+
+// Heartbeat period in seconds.
+#ifndef BLYNK_HEARTBEAT
+#define BLYNK_HEARTBEAT      10
+#endif
+
+// Network timeout in milliseconds.
+#ifndef BLYNK_TIMEOUT_MS
+#define BLYNK_TIMEOUT_MS     2000UL
+#endif
+
+// Limit the amount of outgoing commands.
+#ifndef BLYNK_MSG_LIMIT
+#define BLYNK_MSG_LIMIT      20
+#endif
+
+// Limit the incoming command length.
+#ifndef BLYNK_MAX_READBYTES
+#define BLYNK_MAX_READBYTES  256
+#endif
+
+// Limit the outgoing command length.
+#ifndef BLYNK_MAX_SENDBYTES
+#define BLYNK_MAX_SENDBYTES  128
+#endif
+
+// Uncomment to disable built-in analog and digital operations.
+//#define BLYNK_NO_BUILTIN
+
+// Uncomment to disable providing info about device to the server.
+//#define BLYNK_NO_INFO
+
+// Uncomment to enable debug prints.
+//#define BLYNK_DEBUG
+
+// Uncomment to enable experimental functions.
+//#define BLYNK_EXPERIMENTAL
+
+// Uncomment to disable all float/double usage
+//#define BLYNK_NO_FLOAT
+
+// Uncomment to switch to direct-connect mode
+//#define BLYNK_USE_DIRECT_CONNECT
+
+
+// Uncomment to append command body to header (uses more RAM)
+//#define BLYNK_SEND_ATOMIC
+
+// Split whole command into chunks (in bytes)
+//#define BLYNK_SEND_CHUNK 64
+
+// Wait after sending each chunk (in milliseconds)
+//#define BLYNK_SEND_THROTTLE 10
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkDebug.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,252 @@
+/**
+ * @file       BlynkDebug.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Debug utilities
+ *
+ */
+
+#ifndef BlynkDebug_h
+#define BlynkDebug_h
+
+#include <Blynk/BlynkConfig.h>
+#include <stddef.h>
+#ifdef ESP8266
+    extern "C" {
+    #include "ets_sys.h"
+    #include "os_type.h"
+    #include "mem.h"
+    }
+#else
+    #include <inttypes.h>
+#endif
+
+#if defined(ARDUINO_ARCH_ARC32)
+    typedef uint64_t millis_time_t;
+#else
+    typedef uint32_t millis_time_t;
+#endif
+
+#if defined(SPARK) || defined(PARTICLE)
+    #include "application.h"
+#endif
+
+#if defined(ARDUINO)
+    #if ARDUINO >= 100
+        #include "Arduino.h"
+    #else
+        #include "WProgram.h"
+    #endif
+#endif
+
+#if !defined(ARDUINO) || (ARDUINO < 151)
+    #define BLYNK_NO_YIELD
+#endif
+
+// General defines
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+#define BLYNK_ATTR_PACKED __attribute__ ((__packed__))
+#define BLYNK_NORETURN __attribute__ ((noreturn))
+
+// Causes problems on some platforms
+#define BLYNK_FORCE_INLINE inline //__attribute__((always_inline))
+
+#if defined(__AVR__)
+    #include <avr/pgmspace.h>
+    #define BLYNK_HAS_PROGMEM
+    #define BLYNK_PROGMEM PROGMEM
+    #define BLYNK_F(s) F(s)
+    #define BLYNK_PSTR(s) PSTR(s)
+#else
+    #define BLYNK_PROGMEM
+    #define BLYNK_F(s) s
+    #define BLYNK_PSTR(s) s
+#endif
+
+#ifndef LED_BUILTIN
+# define LED_BUILTIN 2
+#endif
+
+// Diagnostic defines
+
+size_t BlynkFreeRam();
+void BlynkReset() BLYNK_NORETURN;
+void BlynkFatal() BLYNK_NORETURN;
+
+#define BLYNK_FATAL(msg)     { BLYNK_LOG1(msg); BlynkFatal(); }
+#define BLYNK_LOG_RAM()      { BLYNK_LOG2(BLYNK_F("Free RAM: "), BlynkFreeRam()); }
+#define BLYNK_LOG_FN()       BLYNK_LOG3(BLYNK_F(__FUNCTION__), '@', __LINE__);
+#define BLYNK_LOG_TROUBLE(t) BLYNK_LOG2(BLYNK_F("Trouble detected: http://docs.blynk.cc/#troubleshooting-"), t)
+
+#ifndef BLYNK_PRINT
+#undef BLYNK_DEBUG
+#endif
+
+#ifdef BLYNK_PRINT
+
+    #if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE)
+
+#if defined(ARDUINO_ARCH_ARC32)
+        // This will cause error - on purpose
+        #define BLYNK_LOG(msg, ...)  BLYNK_LOG_UNAVAILABLE(msg, ##__VA_ARGS__)
+#else
+        #define BLYNK_LOG(msg, ...)  blynk_dbg_print(BLYNK_PSTR(msg), ##__VA_ARGS__)
+#endif
+
+        #define BLYNK_LOG1(p1)            { BLYNK_LOG_TIME(); BLYNK_PRINT.println(p1); }
+        #define BLYNK_LOG2(p1,p2)         { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.println(p2); }
+        #define BLYNK_LOG3(p1,p2,p3)      { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.print(p2); BLYNK_PRINT.println(p3); }
+        #define BLYNK_LOG4(p1,p2,p3,p4)   { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.print(p2); BLYNK_PRINT.print(p3); BLYNK_PRINT.println(p4); }
+        #define BLYNK_LOG6(p1,p2,p3,p4,p5,p6) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.print(p2); BLYNK_PRINT.print(p3); BLYNK_PRINT.print(p4); BLYNK_PRINT.print(p5); BLYNK_PRINT.println(p6); }
+        #define BLYNK_LOG_IP(msg, ip)     { BLYNK_LOG_TIME(); BLYNK_PRINT.print(BLYNK_F(msg)); \
+                                            BLYNK_PRINT.print(ip[0]); BLYNK_PRINT.print('.');  \
+                                            BLYNK_PRINT.print(ip[1]); BLYNK_PRINT.print('.');  \
+                                            BLYNK_PRINT.print(ip[2]); BLYNK_PRINT.print('.');  \
+                                            BLYNK_PRINT.println(ip[3]); }
+        #define BLYNK_LOG_IP_REV(msg, ip) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(BLYNK_F(msg)); \
+                                            BLYNK_PRINT.print(ip[3]); BLYNK_PRINT.print('.');  \
+                                            BLYNK_PRINT.print(ip[2]); BLYNK_PRINT.print('.');  \
+                                            BLYNK_PRINT.print(ip[1]); BLYNK_PRINT.print('.');  \
+                                            BLYNK_PRINT.println(ip[0]); }
+
+        static
+        void BLYNK_LOG_TIME() {
+            BLYNK_PRINT.print('[');
+            BLYNK_PRINT.print(millis());
+            BLYNK_PRINT.print(BLYNK_F("] "));
+        }
+
+#ifdef BLYNK_DEBUG
+        #include <ctype.h>
+        #define BLYNK_DBG_BREAK()    { for(;;); }
+        #define BLYNK_ASSERT(expr)   { if(!(expr)) { BLYNK_LOG2(BLYNK_F("Assertion failed: "), BLYNK_F(#expr)); BLYNK_DBG_BREAK() } }
+
+        static
+        void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) {
+            if (len) {
+                BLYNK_LOG_TIME();
+                BLYNK_PRINT.print(msg);
+                int l2 = len;
+                const uint8_t* octets = (const uint8_t*)addr;
+                bool prev_print = true;
+                while (l2--) {
+                    const uint8_t c = *octets++ & 0xFF;
+                    if (isprint(c)) {
+                        if (!prev_print) { BLYNK_PRINT.print(']'); }
+                        BLYNK_PRINT.print((char)c);
+                        prev_print = true;
+                    } else {
+                        BLYNK_PRINT.print(prev_print?'[':'|');
+                        if (c < 0x10) { BLYNK_PRINT.print('0'); }
+                        BLYNK_PRINT.print(c, HEX);
+                        prev_print = false;
+                    }
+                }
+                BLYNK_PRINT.println(prev_print?"":"]");
+            }
+        }
+#endif
+
+        #if !defined(ARDUINO_ARCH_ARC32)
+        #include <stdio.h>
+        #include <stdarg.h>
+
+        static
+        void blynk_dbg_print(const char* BLYNK_PROGMEM fmt, ...)
+        {
+            va_list ap;
+            va_start(ap, fmt);
+            char buff[128];
+            BLYNK_PRINT.print('[');
+            BLYNK_PRINT.print(millis());
+            BLYNK_PRINT.print(F("] "));
+#if defined(__AVR__)
+            vsnprintf_P(buff, sizeof(buff), fmt, ap);
+#else
+            vsnprintf(buff, sizeof(buff), fmt, ap);
+#endif
+            BLYNK_PRINT.println(buff);
+            va_end(ap);
+        }
+        #endif // ARDUINO_ARCH_ARC32
+    /*#elif defined(MBED_LIBRARY_VERSION)
+        void delay(unsigned long ms);
+        unsigned long millis(void);
+    */
+    #elif defined(LINUX)
+
+        #include <assert.h>
+        #include <stdio.h>
+        #include <string.h>
+        #include <errno.h>
+        #include <signal.h>
+
+        #include <iostream>
+        using namespace std;
+        #define BLYNK_LOG(msg, ...)       { fprintf(BLYNK_PRINT, "[%ld] " msg "\n", millis(), ##__VA_ARGS__); }
+        #define BLYNK_LOG1(p1)            { BLYNK_LOG_TIME(); cout << p1 << endl; }
+        #define BLYNK_LOG2(p1,p2)         { BLYNK_LOG_TIME(); cout << p1 << p2 << endl; }
+        #define BLYNK_LOG3(p1,p2,p3)      { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << endl; }
+        #define BLYNK_LOG4(p1,p2,p3,p4)   { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << p4 << endl; }
+        #define BLYNK_LOG6(p1,p2,p3,p4,p5,p6)   { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << p4 << p5 << p6 << endl; }
+
+        #define BLYNK_LOG_TIME() cout << '[' << millis() << "] ";
+
+#ifdef BLYNK_DEBUG
+        #define BLYNK_DBG_BREAK()    raise(SIGTRAP);
+        #define BLYNK_ASSERT(expr)   assert(expr)
+
+        static
+        void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) {
+            BLYNK_LOG_TIME();
+            fprintf(BLYNK_PRINT, msg);
+            int l2 = len;
+            const uint8_t* octets = (const uint8_t*)addr;
+            bool prev_print = true;
+            while (l2--) {
+                const uint8_t c = *octets++ & 0xFF;
+                if (c > 31) {
+                    if (!prev_print) { fputc(']', BLYNK_PRINT); }
+                    fputc((char)c, BLYNK_PRINT);
+                    prev_print = true;
+                } else {
+                    fputc(prev_print?'[':'|', BLYNK_PRINT);
+                    fprintf(BLYNK_PRINT, "%02x", c);
+                    prev_print = false;
+                }
+            }
+            fprintf(BLYNK_PRINT, "%s\n", prev_print?"":"]");
+        }
+#endif
+
+    #else
+
+        #warning Could not detect platform
+
+    #endif
+
+#endif
+
+#ifndef BLYNK_LOG
+    #define BLYNK_LOG(...)
+    #define BLYNK_LOG1(p1)
+    #define BLYNK_LOG2(p1,p2)
+    #define BLYNK_LOG3(p1,p2,p3)
+    #define BLYNK_LOG4(p1,p2,p3,p4)
+    #define BLYNK_LOG6(p1,p2,p3,p4,p5,p6)
+    #define BLYNK_LOG_IP(msg, ip)
+    #define BLYNK_LOG_IP_REV(msg, ip)
+#endif
+
+#ifndef BLYNK_DBG_BREAK
+    #define BLYNK_DBG_BREAK()
+    #define BLYNK_ASSERT(expr)
+    #define BLYNK_DBG_DUMP(msg, addr, len)
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkDetectDevice.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,232 @@
+/**
+ * @file       BlynkDetectDevice.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy
+ * @date       May 2016
+ * @brief
+ *
+ */
+
+#ifndef BlynkDetectDevice_h
+#define BlynkDetectDevice_h
+
+#ifndef BLYNK_INFO_CPU
+
+    /******************************************
+     * ATmega
+     */
+
+    #if   defined(__AVR_ATmega168__)
+    #define BLYNK_INFO_CPU      "ATmega168"
+    #elif defined(__AVR_ATmega328P__)
+    #define BLYNK_INFO_CPU      "ATmega328P"
+    #elif defined(__AVR_ATmega1280__)
+    #define BLYNK_INFO_CPU      "ATmega1280"
+    #elif defined(__AVR_ATmega1284__)
+    #define BLYNK_INFO_CPU      "ATmega1284"
+    #elif defined(__AVR_ATmega2560__)
+    #define BLYNK_INFO_CPU      "ATmega2560"
+    #elif defined(__AVR_ATmega32U4__)
+    #define BLYNK_INFO_CPU      "ATmega32U4"
+    #elif defined(__SAM3X8E__)
+    #define BLYNK_INFO_CPU      "AT91SAM3X8E"
+
+    /******************************************
+     * ATtiny
+     */
+
+    #elif defined(__AVR_ATtiny25__)
+    #define BLYNK_INFO_CPU      "ATtiny25"
+    #elif defined(__AVR_ATtiny45__)
+    #define BLYNK_INFO_CPU      "ATtiny45"
+    #elif defined(__AVR_ATtiny85__)
+    #define BLYNK_INFO_CPU      "ATtiny85"
+    #elif defined(__AVR_ATtiny24__)
+    #define BLYNK_INFO_CPU      "ATtiny24"
+    #elif defined(__AVR_ATtiny44__)
+    #define BLYNK_INFO_CPU      "ATtiny44"
+    #elif defined(__AVR_ATtiny84__)
+    #define BLYNK_INFO_CPU      "ATtiny84"
+    #elif defined(__AVR_ATtiny2313__)
+    #define BLYNK_INFO_CPU      "ATtiny2313"
+    #elif defined(__AVR_ATtiny4313__)
+    #define BLYNK_INFO_CPU      "ATtiny4313"
+    #endif
+#endif
+
+#ifndef BLYNK_INFO_DEVICE
+
+    #if   defined(ENERGIA)
+        #define BLYNK_INFO_DEVICE  "Energia"
+
+        #if   defined(__MSP430F5529__)
+        #define BLYNK_INFO_CPU  "MSP430F5529"
+        #define BLYNK_NO_FLOAT
+        #endif
+
+    #elif defined(LINUX)
+
+        #define BLYNK_INFO_DEVICE  "Linux"
+
+    #elif defined(SPARK) || defined(PARTICLE)
+
+        #if PLATFORM_ID==0
+        #define BLYNK_INFO_DEVICE  "Particle Core"
+        #elif PLATFORM_ID==6
+        #define BLYNK_INFO_DEVICE  "Particle Photon"
+        #elif PLATFORM_ID==8
+        #define BLYNK_INFO_DEVICE  "Particle P1"
+        #elif PLATFORM_ID==9
+        #define BLYNK_INFO_DEVICE  "Particle Ethernet"
+        #elif PLATFORM_ID==10
+        #define BLYNK_INFO_DEVICE  "Particle Electron"
+        #elif PLATFORM_ID==82
+        #define BLYNK_INFO_DEVICE  "Digistump Oak"
+        #elif PLATFORM_ID==88
+        #define BLYNK_INFO_DEVICE  "RedBear Duo"
+        #elif PLATFORM_ID==103
+        #define BLYNK_INFO_DEVICE  "Bluz"
+        #else
+        #warning "Cannot detect board type"
+        #define BLYNK_INFO_DEVICE  "Particle"
+        #endif
+
+    #elif defined(MBED_LIBRARY_VERSION)
+
+        #define BLYNK_INFO_DEVICE  "MBED"
+
+    #elif defined(ARDUINO) && defined(MPIDE)
+        #define BLYNK_NO_YIELD
+
+        #if   defined(_BOARD_UNO_)
+        #define BLYNK_INFO_DEVICE  "chipKIT Uno32"
+        #else
+        #define BLYNK_INFO_DEVICE  "chipKIT"
+        #endif
+
+    #elif defined(ARDUINO)
+
+        /* Arduino AVR */
+        #if   defined(ARDUINO_AVR_NANO)
+        #define BLYNK_INFO_DEVICE  "Arduino Nano"
+        #elif defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_DUEMILANOVE)
+        #define BLYNK_INFO_DEVICE  "Arduino Uno"
+        #elif defined(ARDUINO_AVR_YUN)
+        #define BLYNK_INFO_DEVICE  "Arduino Yun"
+        #elif defined(ARDUINO_AVR_MINI)
+        #define BLYNK_INFO_DEVICE  "Arduino Mini"
+        #elif defined(ARDUINO_AVR_ETHERNET)
+        #define BLYNK_INFO_DEVICE  "Arduino Ethernet"
+        #elif defined(ARDUINO_AVR_FIO)
+        #define BLYNK_INFO_DEVICE  "Arduino Fio"
+        #elif defined(ARDUINO_AVR_BT)
+        #define BLYNK_INFO_DEVICE  "Arduino BT"
+        #elif defined(ARDUINO_AVR_PRO)
+        #define BLYNK_INFO_DEVICE  "Arduino Pro"
+        #elif defined(ARDUINO_AVR_NG)
+        #define BLYNK_INFO_DEVICE  "Arduino NG"
+        #elif defined(ARDUINO_AVR_GEMMA)
+        #define BLYNK_INFO_DEVICE  "Arduino Gemma"
+        #elif defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)
+        #define BLYNK_INFO_DEVICE  "Arduino Mega"
+        #elif defined(ARDUINO_AVR_ADK)
+        #define BLYNK_INFO_DEVICE  "Arduino Mega ADK"
+        #elif defined(ARDUINO_AVR_LEONARDO)
+        #define BLYNK_INFO_DEVICE  "Arduino Leonardo"
+        #elif defined(ARDUINO_AVR_MICRO)
+        #define BLYNK_INFO_DEVICE  "Arduino Micro"
+        #elif defined(ARDUINO_AVR_ESPLORA)
+        #define BLYNK_INFO_DEVICE  "Arduino Esplora"
+        #elif defined(ARDUINO_AVR_LILYPAD)
+        #define BLYNK_INFO_DEVICE  "Lilypad"
+        #elif defined(ARDUINO_AVR_LILYPAD_USB)
+        #define BLYNK_INFO_DEVICE  "Lilypad USB"
+        #elif defined(ARDUINO_AVR_ROBOT_MOTOR)
+        #define BLYNK_INFO_DEVICE  "Robot Motor"
+        #elif defined(ARDUINO_AVR_ROBOT_CONTROL)
+        #define BLYNK_INFO_DEVICE  "Robot Control"
+
+        /* Arduino SAM/SAMD */
+        #elif defined(ARDUINO_SAM_DUE)
+        #define BLYNK_INFO_DEVICE  "Arduino Due"
+        #elif defined(ARDUINO_SAMD_ZERO)
+        #define BLYNK_INFO_DEVICE  "Arduino Zero"
+        #elif defined(ARDUINO_SAMD_MKR1000)
+        #define BLYNK_INFO_DEVICE  "Arduino MKR1000"
+
+        /* Intel */
+        #elif defined(ARDUINO_GALILEO)
+        #define BLYNK_INFO_DEVICE  "Galileo"
+        #elif defined(ARDUINO_GALILEOGEN2)
+        #define BLYNK_INFO_DEVICE  "Galileo Gen2"
+        #elif defined(ARDUINO_EDISON)
+        #define BLYNK_INFO_DEVICE  "Edison"
+        #elif defined(ARDUINO_ARCH_ARC32) // TODO
+        #define BLYNK_INFO_DEVICE  "Arduino 101"
+
+        /* Konekt */
+        #elif defined(ARDUINO_DASH)
+        #define BLYNK_INFO_DEVICE  "Dash"
+        #elif defined(ARDUINO_DASHPRO)
+        #define BLYNK_INFO_DEVICE  "Dash Pro"
+
+        /* Red Bear Lab */
+        #elif defined(ARDUINO_RedBear_Duo)
+        #define BLYNK_INFO_DEVICE  "RedBear Duo"
+        #elif defined(ARDUINO_BLEND)
+        #define BLYNK_INFO_DEVICE  "Blend"
+        #elif defined(ARDUINO_BLEND_MICRO_8MHZ) || defined(ARDUINO_BLEND_MICRO_16MHZ)
+        #define BLYNK_INFO_DEVICE  "Blend Micro"
+        #elif defined(ARDUINO_RBL_nRF51822)
+        #define BLYNK_INFO_DEVICE  "BLE Nano"
+
+        /* ESP8266 */
+        #elif defined(ARDUINO_ESP8266_ESP01)
+        #define BLYNK_INFO_DEVICE  "ESP8266"
+        #elif defined(ARDUINO_ESP8266_ESP12)
+        #define BLYNK_INFO_DEVICE  "ESP-12"
+        #elif defined(ARDUINO_ESP8266_NODEMCU)
+        #define BLYNK_INFO_DEVICE  "NodeMCU"
+        #elif defined(ARDUINO_ESP8266_THING)
+        #define BLYNK_INFO_DEVICE  "Esp Thing"
+        #elif defined(ARDUINO_ESP8266_THING_DEV)
+        #define BLYNK_INFO_DEVICE  "Esp Thing Dev"
+
+        /* Digistump */
+        #elif defined(ARDUINO_ESP8266_OAK)
+        #define BLYNK_INFO_DEVICE  "Oak"
+        #elif defined(ARDUINO_AVR_DIGISPARK)
+        #define BLYNK_INFO_DEVICE  "Digispark"
+        #elif defined(ARDUINO_AVR_DIGISPARKPRO)
+        #define BLYNK_INFO_DEVICE  "Digispark Pro"
+
+        /* Microduino */
+        #elif defined(ARDUINO_AVR_USB)
+        #define BLYNK_INFO_DEVICE  "CoreUSB"
+        #elif defined(ARDUINO_AVR_PLUS)
+        #define BLYNK_INFO_DEVICE  "Core+"
+        #elif defined(ARDUINO_AVR_RF)
+        #define BLYNK_INFO_DEVICE  "CoreRF"
+
+        /* Wildfire */
+        #elif defined(ARDUINO_WILDFIRE_V2)
+        #define BLYNK_INFO_DEVICE  "Wildfire V2"
+        #elif defined(ARDUINO_WILDFIRE_V3)
+        #define BLYNK_INFO_DEVICE  "Wildfire V3"
+        #elif defined(ARDUINO_WILDFIRE_V4)
+        #define BLYNK_INFO_DEVICE  "Wildfire V4"
+
+        /* Simblee */
+        #elif defined(__Simblee__) // TODO: ARDUINO_SIMBLEE bug?
+        #define BLYNK_INFO_DEVICE  "Simblee"
+
+        #else
+        #warning "Cannot detect board type"
+        #define BLYNK_INFO_DEVICE  "Arduino"
+        #endif
+
+	#endif
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkHandlers.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,218 @@
+/**
+ * @file       BlynkHandlers.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Handlers for virtual pin operations
+ *
+ */
+
+#ifndef BlynkHandlers_h
+#define BlynkHandlers_h
+
+#include <Blynk/BlynkConfig.h>
+#include <Blynk/BlynkParam.h>
+
+// Helper macro
+
+#define V0  0
+#define V1  1
+#define V2  2
+#define V3  3
+#define V4  4
+#define V5  5
+#define V6  6
+#define V7  7
+#define V8  8
+#define V9  9
+#define V10 10
+#define V11 11
+#define V12 12
+#define V13 13
+#define V14 14
+#define V15 15
+#define V16 16
+#define V17 17
+#define V18 18
+#define V19 19
+#define V20 20
+#define V21 21
+#define V22 22
+#define V23 23
+#define V24 24
+#define V25 25
+#define V26 26
+#define V27 27
+#define V28 28
+#define V29 29
+#define V30 30
+#define V31 31
+
+#define BLYNK_CONCAT(a, b) a ## b
+#define BLYNK_CONCAT2(a, b) BLYNK_CONCAT(a, b)
+
+// Initial syntax:
+#define BLYNK_WRITE_2(pin) \
+    void BlynkWidgetWrite ## pin (BlynkReq& request, const BlynkParam& param)
+
+#define BLYNK_READ_2(pin)  \
+    void BlynkWidgetRead ## pin  (BlynkReq& request)
+
+#define BLYNK_WRITE_DEFAULT() BLYNK_WRITE_2(Default)
+#define BLYNK_READ_DEFAULT()  BLYNK_READ_2(Default)
+
+#define BLYNK_WRITE(pin)      BLYNK_WRITE_2(pin)
+#define BLYNK_READ(pin)       BLYNK_READ_2(pin)
+
+// New, more readable syntax:
+#define BLYNK_IN_2(pin)  \
+    void BlynkWidgetWrite ## pin (BlynkReq& request, const BlynkParam& getValue)
+
+#define BLYNK_OUT_2(pin) \
+    void BlynkWidgetRead ## pin  (BlynkReq& request)
+
+#define BLYNK_IN_DEFAULT()   BLYNK_IN_2(Default)
+#define BLYNK_OUT_DEFAULT()  BLYNK_OUT_2(Default)
+
+#define BLYNK_IN(pin)        BLYNK_IN_2(pin)
+#define BLYNK_OUT(pin)       BLYNK_OUT_2(pin)
+
+// Additional handlers
+#define BLYNK_CONNECTED()    void BlynkOnConnected()
+#define BLYNK_DISCONNECTED() void BlynkOnDisconnected()
+
+// Advanced functions
+
+class BlynkAttachWidgetHelper {
+public:
+	template<typename T>
+	explicit BlynkAttachWidgetHelper(T& widget, uint8_t vPin) {
+		widget.setVPin(vPin);
+	}
+};
+
+// Could use __attribute__ ((constructor)), but hope for better portability
+#define BLYNK_ATTACH_WIDGET(widget, pin)	\
+	static BlynkAttachWidgetHelper BLYNK_CONCAT2(blnk_widget_helper_, __COUNTER__)((widget), (pin)); \
+    BLYNK_WRITE(pin) { (widget).onWrite(request, param); }
+
+#define BLYNK_VAR_INT(name, pin)	int name;  \
+    BLYNK_WRITE(pin) { name = param.asInt(); } \
+    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }
+
+#define BLYNK_VAR_LONG(name, pin)	long name;  \
+    BLYNK_WRITE(pin) { name = param.asLong(); } \
+    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }
+
+#ifndef BLYNK_NO_FLOAT
+#define BLYNK_VAR_DOUBLE(name, pin)	double name;  \
+    BLYNK_WRITE(pin) { name = param.asDouble(); } \
+    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }
+#endif
+
+#ifdef ARDUINO
+#define BLYNK_VAR_STRING(name, pin)	String name;  \
+    BLYNK_WRITE(pin) { name = param.asStr(); } \
+    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }
+#endif
+
+// Default read/write handlers (you can redefine them in your code)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct BlynkReq
+{
+    uint8_t pin;
+};
+
+typedef void (*WidgetReadHandler)(BlynkReq& request);
+typedef void (*WidgetWriteHandler)(BlynkReq& request, const BlynkParam& param);
+
+WidgetReadHandler GetReadHandler(uint8_t pin);
+WidgetWriteHandler GetWriteHandler(uint8_t pin);
+
+// Declare placeholders
+BLYNK_READ();
+BLYNK_WRITE();
+void BlynkNoOpCbk();
+
+// Declare all pin handlers (you can redefine them in your code)
+BLYNK_CONNECTED();
+BLYNK_DISCONNECTED();
+
+BLYNK_READ_DEFAULT();
+BLYNK_WRITE_DEFAULT();
+
+BLYNK_READ(0 );
+BLYNK_READ(1 );
+BLYNK_READ(2 );
+BLYNK_READ(3 );
+BLYNK_READ(4 );
+BLYNK_READ(5 );
+BLYNK_READ(6 );
+BLYNK_READ(7 );
+BLYNK_READ(8 );
+BLYNK_READ(9 );
+BLYNK_READ(10);
+BLYNK_READ(11);
+BLYNK_READ(12);
+BLYNK_READ(13);
+BLYNK_READ(14);
+BLYNK_READ(15);
+BLYNK_READ(16);
+BLYNK_READ(17);
+BLYNK_READ(18);
+BLYNK_READ(19);
+BLYNK_READ(20);
+BLYNK_READ(21);
+BLYNK_READ(22);
+BLYNK_READ(23);
+BLYNK_READ(24);
+BLYNK_READ(25);
+BLYNK_READ(26);
+BLYNK_READ(27);
+BLYNK_READ(28);
+BLYNK_READ(29);
+BLYNK_READ(30);
+BLYNK_READ(31);
+
+BLYNK_WRITE(0 );
+BLYNK_WRITE(1 );
+BLYNK_WRITE(2 );
+BLYNK_WRITE(3 );
+BLYNK_WRITE(4 );
+BLYNK_WRITE(5 );
+BLYNK_WRITE(6 );
+BLYNK_WRITE(7 );
+BLYNK_WRITE(8 );
+BLYNK_WRITE(9 );
+BLYNK_WRITE(10);
+BLYNK_WRITE(11);
+BLYNK_WRITE(12);
+BLYNK_WRITE(13);
+BLYNK_WRITE(14);
+BLYNK_WRITE(15);
+BLYNK_WRITE(16);
+BLYNK_WRITE(17);
+BLYNK_WRITE(18);
+BLYNK_WRITE(19);
+BLYNK_WRITE(20);
+BLYNK_WRITE(21);
+BLYNK_WRITE(22);
+BLYNK_WRITE(23);
+BLYNK_WRITE(24);
+BLYNK_WRITE(25);
+BLYNK_WRITE(26);
+BLYNK_WRITE(27);
+BLYNK_WRITE(28);
+BLYNK_WRITE(29);
+BLYNK_WRITE(30);
+BLYNK_WRITE(31);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkParam.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,299 @@
+/**
+ * @file       BlynkParam.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Container for handler parameters
+ *
+ */
+
+#ifndef BlynkParam_h
+#define BlynkParam_h
+
+#include <string.h>
+#include <stdlib.h>
+#include <Blynk/BlynkConfig.h>
+#include <Blynk/BlynkDebug.h>
+
+#define BLYNK_PARAM_KV(k, v) k "\0" v "\0"
+
+class BlynkParam
+{
+public:
+    class iterator
+    {
+    public:
+        iterator(char* c) : ptr(c) {}
+        static iterator invalid() { return iterator(NULL); }
+
+        operator const char* () const   { return asStr(); }
+        operator int () const           { return asInt(); }
+        const char* asStr() const       { return ptr; }
+        const char* asString() const    { return ptr; }
+        int         asInt() const       { return atoi(ptr); }
+        long        asLong() const      { return atol(ptr); }
+#ifndef BLYNK_NO_FLOAT
+        double      asDouble() const    { return atof(ptr); }
+#endif
+        bool isValid() const            { return ptr != NULL; }
+
+        bool operator <  (const iterator& it) const { return ptr < it.ptr; }
+        bool operator >= (const iterator& it) const { return ptr >= it.ptr; }
+
+        iterator& operator ++() {
+            ptr += strlen(ptr)+1;
+            return *this;
+        }
+    private:
+        const char* ptr;
+    };
+
+public:
+    explicit
+    BlynkParam(void* addr, size_t length)
+        : buff((char*)addr), len(length), buff_size(length)
+    {}
+
+    explicit
+    BlynkParam(void* addr, size_t length, size_t buffsize)
+        : buff((char*)addr), len(length), buff_size(buffsize)
+    {}
+
+    const char* asStr() const       { return buff; }
+    const char* asString() const    { return buff; }
+    int         asInt() const       { return atoi(buff); }
+    long        asLong() const      { return atol(buff); }
+#ifndef BLYNK_NO_FLOAT
+    double      asDouble() const    { return atof(buff); }
+#endif
+
+    iterator begin() const { return iterator(buff); }
+    iterator end() const   { return iterator(buff+len); }
+
+    iterator operator[](int index) const;
+    iterator operator[](const char* key) const;
+
+    void*  getBuffer() const { return (void*)buff; }
+    size_t getLength() const { return len; }
+
+    // Modification
+    void add(int value);
+    void add(unsigned int value);
+    void add(long value);
+    void add(unsigned long value);
+#ifndef BLYNK_NO_FLOAT
+    void add(float value);
+    void add(double value);
+#endif
+    void add(const char* str);
+    void add(const void* b, size_t l);
+#if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE)
+    void add(const String& str);
+    void add(String& str);
+#endif
+
+    template <typename TV>
+    void add_key(const char* key, const TV& val) {
+        add(key);
+        add(val);
+    }
+
+private:
+    char*	buff;
+    size_t	len;
+    size_t	buff_size;
+};
+
+inline
+BlynkParam::iterator BlynkParam::operator[](int index) const
+{
+    const iterator e = end();
+    for (iterator it = begin(); it < e; ++it) {
+        if (!index--) {
+            return it;
+        }
+    }
+    return iterator::invalid();
+}
+
+inline
+BlynkParam::iterator BlynkParam::operator[](const char* key) const
+{
+    const iterator e = end();
+    for (iterator it = begin(); it < e; ++it) {
+        if (!strcmp(it.asStr(), key)) {
+            return ++it;
+        }
+        ++it;
+        if (it >= e) break;
+    }
+    return iterator::invalid();
+}
+
+inline
+void BlynkParam::add(const void* b, size_t l)
+{
+    if (len + l > buff_size)
+        return;
+    memcpy(buff+len, b, l);
+    len += l;
+}
+
+inline
+void BlynkParam::add(const char* str)
+{
+    add(str, strlen(str)+1);
+}
+
+#if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE)
+inline
+void BlynkParam::add(const String& str)
+{
+    size_t len = str.length()+1;
+    char buff[len];
+#if defined(ARDUINO_AVR_DIGISPARK)
+    const_cast<String&>(str).toCharArray(buff, len);
+#else
+    str.toCharArray(buff, len);
+#endif
+    BlynkParam::add(buff, len);
+}
+
+inline
+void BlynkParam::add(String& str)
+{
+    size_t len = str.length()+1;
+    char buff[len];
+    str.toCharArray(buff, len);
+    BlynkParam::add(buff, len);
+}
+#endif
+
+#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
+
+    #include <stdlib.h>
+
+	inline
+    void BlynkParam::add(int value)
+    {
+        char str[2 + 8 * sizeof(value)];
+        itoa(value, str, 10);
+        add(str);
+    }
+
+	inline
+    void BlynkParam::add(unsigned int value)
+    {
+        char str[1 + 8 * sizeof(value)];
+        utoa(value, str, 10);
+        add(str);
+    }
+
+	inline
+    void BlynkParam::add(long value)
+    {
+        char str[2 + 8 * sizeof(value)];
+        ltoa(value, str, 10);
+        add(str);
+    }
+
+	inline
+    void BlynkParam::add(unsigned long value)
+    {
+        char str[1 + 8 * sizeof(value)];
+        ultoa(value, str, 10);
+        add(str);
+    }
+
+#ifndef BLYNK_NO_FLOAT
+
+	inline
+    void BlynkParam::add(float value)
+    {
+        char str[33];
+        dtostrf(value, 5, 3, str);
+        add(str);
+    }
+
+	inline
+    void BlynkParam::add(double value)
+    {
+        char str[33];
+        dtostrf(value, 5, 3, str);
+        add(str);
+    }
+#endif
+
+#else
+
+    #include <stdio.h>
+
+	inline
+    void BlynkParam::add(int value)
+    {
+        len += snprintf(buff+len, buff_size-len, "%i", value)+1;
+    }
+
+	inline
+    void BlynkParam::add(unsigned int value)
+    {
+        len += snprintf(buff+len, buff_size-len, "%u", value)+1;
+    }
+
+	inline
+    void BlynkParam::add(long value)
+    {
+        len += snprintf(buff+len, buff_size-len, "%li", value)+1;
+    }
+
+	inline
+    void BlynkParam::add(unsigned long value)
+    {
+        len += snprintf(buff+len, buff_size-len, "%lu", value)+1;
+    }
+
+#ifndef BLYNK_NO_FLOAT
+
+#if defined(ESP8266)
+
+	extern char* dtostrf_internal(double number, signed char width, unsigned char prec, char *s);
+
+	inline
+    void BlynkParam::add(float value)
+    {
+        char str[33];
+        dtostrf_internal(value, 5, 3, str);
+        add(str);
+    }
+
+	inline
+    void BlynkParam::add(double value)
+    {
+        char str[33];
+        dtostrf_internal(value, 5, 3, str);
+        add(str);
+    }
+
+#else
+
+	inline
+    void BlynkParam::add(float value)
+    {
+        len += snprintf(buff+len, buff_size-len, "%2.3f", value)+1;
+    }
+
+	inline
+    void BlynkParam::add(double value)
+    {
+        len += snprintf(buff+len, buff_size-len, "%2.3f", value)+1;
+    }
+
+#endif
+
+#endif
+
+#endif
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkProtocol.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,441 @@
+/**
+ * @file       BlynkProtocol.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Blynk protocol implementation
+ *
+ */
+
+#ifndef BlynkProtocol_h
+#define BlynkProtocol_h
+
+#include <string.h>
+#include <stdlib.h>
+#include <Blynk/BlynkDebug.h>
+#include <Blynk/BlynkProtocolDefs.h>
+#include <Blynk/BlynkApi.h>
+#include <utility/BlynkUtility.h>
+
+template <class Transp>
+class BlynkProtocol
+    : public BlynkApi< BlynkProtocol<Transp> >
+{
+    friend class BlynkApi< BlynkProtocol<Transp> >;
+public:
+    enum BlynkState {
+        CONNECTING,
+        CONNECTED,
+        DISCONNECTED,
+    };
+
+    BlynkProtocol(Transp& transp)
+        : conn(transp)
+        , authkey(NULL)
+        , lastActivityIn(0)
+        , lastActivityOut(0)
+        , lastHeartbeat(0)
+#ifdef BLYNK_MSG_LIMIT
+        , deltaCmd(0)
+#endif
+        , currentMsgId(0)
+        , state(CONNECTING)
+    {}
+
+    bool connected() { return state == CONNECTED; }
+
+    bool connect(uint32_t timeout = BLYNK_TIMEOUT_MS*3) {
+    	conn.disconnect();
+    	state = CONNECTING;
+    	millis_time_t started = this->getMillis();
+    	while ((state != CONNECTED) &&
+    	       (this->getMillis() - started < timeout))
+    	{
+    		run();
+    	}
+    	return state == CONNECTED;
+    }
+
+    void disconnect() {
+        conn.disconnect();
+        state = DISCONNECTED;
+        BLYNK_LOG1(BLYNK_F("Disconnected"));
+    }
+
+    bool run(bool avail = false);
+
+    void startSession() {
+        //TODO: conn.connect();
+    	state = CONNECTING;
+#ifdef BLYNK_MSG_LIMIT
+        deltaCmd = 1000;
+#endif
+    	currentMsgId = 0;
+    	lastHeartbeat = lastActivityIn = lastActivityOut = this->getMillis(); // TODO: - 5005UL
+    }
+
+    void sendCmd(uint8_t cmd, uint16_t id = 0, const void* data = NULL, size_t length = 0, const void* data2 = NULL, size_t length2 = 0);
+
+private:
+    int readHeader(BlynkHeader& hdr);
+    uint16_t getNextMsgId();
+
+protected:
+    void begin(const char* auth) {
+        BLYNK_LOG1(BLYNK_F("Blynk v" BLYNK_VERSION " on " BLYNK_INFO_DEVICE));
+        this->authkey = auth;
+    }
+    bool processInput(void);
+
+    Transp& conn;
+
+private:
+    const char* authkey;
+    millis_time_t lastActivityIn;
+    millis_time_t lastActivityOut;
+    union {
+    	millis_time_t lastHeartbeat;
+    	millis_time_t lastLogin;
+    };
+#ifdef BLYNK_MSG_LIMIT
+    millis_time_t deltaCmd;
+#endif
+    uint16_t currentMsgId;
+    BlynkState state;
+};
+
+template <class Transp>
+bool BlynkProtocol<Transp>::run(bool avail)
+{
+#if !defined(BLYNK_NO_YIELD)
+    yield();
+#endif
+
+    if (state == DISCONNECTED) {
+        return false;
+    }
+
+    const bool tconn = conn.connected();
+
+    if (tconn) {
+        if (avail || conn.available() > 0) {
+            //BLYNK_LOG2(BLYNK_F("Available: "), conn.available());
+            //const unsigned long t = micros();
+            if (!processInput()) {
+                conn.disconnect();
+// TODO: Only when in direct mode?
+#ifdef BLYNK_USE_DIRECT_CONNECT
+                state = CONNECTING;
+#endif
+                //BlynkOnDisconnected();
+                return false;
+            }
+            //BLYNK_LOG2(BLYNK_F("Proc time: "), micros() - t);
+        }
+    }
+
+    const millis_time_t t = this->getMillis();
+
+    if (state == CONNECTED) {
+        if (!tconn) {
+            state = CONNECTING;
+            lastHeartbeat = t;
+            //BlynkOnDisconnected();
+            return false;
+        }
+
+        if (t - lastActivityIn > (1000UL * BLYNK_HEARTBEAT + BLYNK_TIMEOUT_MS*3)) {
+#ifdef BLYNK_DEBUG
+            BLYNK_LOG6(BLYNK_F("Heartbeat timeout: "), t, BLYNK_F(", "), lastActivityIn, BLYNK_F(", "), lastHeartbeat);
+#else
+            BLYNK_LOG1(BLYNK_F("Heartbeat timeout"));
+#endif
+            conn.disconnect();
+            state = CONNECTING;
+            //BlynkOnDisconnected();
+            return false;
+        } else if ((t - lastActivityIn  > 1000UL * BLYNK_HEARTBEAT ||
+                    t - lastActivityOut > 1000UL * BLYNK_HEARTBEAT) &&
+                    t - lastHeartbeat   > BLYNK_TIMEOUT_MS)
+        {
+            // Send ping if we didn't either send or receive something
+            // for BLYNK_HEARTBEAT seconds
+            sendCmd(BLYNK_CMD_PING);
+            lastHeartbeat = t;
+        }
+#ifndef BLYNK_USE_DIRECT_CONNECT
+    } else if (state == CONNECTING) {
+        if (tconn && (t - lastLogin > BLYNK_TIMEOUT_MS)) {
+            BLYNK_LOG1(BLYNK_F("Login timeout"));
+            conn.disconnect();
+            state = CONNECTING;
+            return false;
+        } else if (!tconn && (t - lastLogin > 5000UL)) {
+            conn.disconnect();
+            if (!conn.connect()) {
+                lastLogin = t;
+                return false;
+            }
+
+#ifdef BLYNK_MSG_LIMIT
+            deltaCmd = 1000;
+#endif
+            sendCmd(BLYNK_CMD_LOGIN, 1, authkey, strlen(authkey));
+            lastLogin = lastActivityOut;
+            return true;
+        }
+#endif
+    }
+    return true;
+}
+
+template <class Transp>
+BLYNK_FORCE_INLINE
+bool BlynkProtocol<Transp>::processInput(void)
+{
+    BlynkHeader hdr;
+    const int ret = readHeader(hdr);
+
+    if (ret == 0) {
+        return true; // Considered OK (no data on input)
+    }
+
+    if (ret < 0 || hdr.msg_id == 0) {
+#ifdef BLYNK_DEBUG
+        BLYNK_LOG1(BLYNK_F("Wrong header on input"));
+#endif
+        return false;
+    }
+
+    if (hdr.type == BLYNK_CMD_RESPONSE) {
+        lastActivityIn = this->getMillis();
+
+#ifndef BLYNK_USE_DIRECT_CONNECT
+        if (state == CONNECTING && (1 == hdr.msg_id)) {
+            switch (hdr.length) {
+            case BLYNK_SUCCESS:
+            case BLYNK_ALREADY_LOGGED_IN:
+                BLYNK_LOG3(BLYNK_F("Ready (ping: "), lastActivityIn-lastHeartbeat, BLYNK_F("ms)."));
+                lastHeartbeat = lastActivityIn;
+                state = CONNECTED;
+                this->sendInfo();
+#if !defined(BLYNK_NO_YIELD)
+                yield();
+#endif
+                BlynkOnConnected();
+                return true;
+            case BLYNK_INVALID_TOKEN:
+                BLYNK_LOG1(BLYNK_F("Invalid auth token"));
+                break;
+            default:
+                BLYNK_LOG2(BLYNK_F("Connect failed. code: "), hdr.length);
+            }
+            return false;
+        }
+        if (BLYNK_NOT_AUTHENTICATED == hdr.length) {
+            return false;
+        }
+#endif
+        // TODO: return code may indicate App presence
+        return true;
+    }
+
+    if (hdr.length > BLYNK_MAX_READBYTES) {
+#ifdef BLYNK_DEBUG
+        BLYNK_LOG2(BLYNK_F("Packet too big: "), hdr.length);
+#endif
+        return false;
+    }
+
+    uint8_t inputBuffer[hdr.length+1]; // Add 1 to zero-terminate
+    if (hdr.length != conn.read(inputBuffer, hdr.length)) {
+#ifdef DEBUG
+        BLYNK_LOG1(BLYNK_F("Can't read body"));
+#endif
+        return false;
+    }
+    inputBuffer[hdr.length] = '\0';
+
+    BLYNK_DBG_DUMP(">", inputBuffer, hdr.length);
+
+    lastActivityIn = this->getMillis();
+
+    switch (hdr.type)
+    {
+#ifdef BLYNK_USE_DIRECT_CONNECT
+    case BLYNK_CMD_LOGIN: {
+        if (!strncmp(authkey, (char*)inputBuffer, 32)) {
+            state = CONNECTED;
+            sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
+            this->sendInfo();
+        } else {
+            sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_INVALID_TOKEN);
+        }
+    } break;
+#endif
+    case BLYNK_CMD_PING: {
+        sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
+    } break;
+    case BLYNK_CMD_HARDWARE:
+    case BLYNK_CMD_BRIDGE: {
+        currentMsgId = hdr.msg_id;
+        this->processCmd(inputBuffer, hdr.length);
+        currentMsgId = 0;
+    } break;
+    default: {
+#ifdef BLYNK_DEBUG
+        BLYNK_LOG2(BLYNK_F("Invalid header type: "), hdr.type);
+#endif
+    } break;
+    }
+
+    return true;
+}
+
+template <class Transp>
+int BlynkProtocol<Transp>::readHeader(BlynkHeader& hdr)
+{
+    size_t rlen = conn.read(&hdr, sizeof(hdr));
+    if (rlen == 0) {
+        return 0;
+    }
+
+    if (sizeof(hdr) != rlen) {
+        return -1;
+    }
+    hdr.msg_id = ntohs(hdr.msg_id);
+    hdr.length = ntohs(hdr.length);
+
+    BLYNK_DBG_DUMP(">", &hdr, sizeof(BlynkHeader));
+    return rlen;
+}
+
+#ifndef BLYNK_SEND_THROTTLE
+#define BLYNK_SEND_THROTTLE 0
+#endif
+
+#ifndef BLYNK_SEND_CHUNK
+#define BLYNK_SEND_CHUNK 1024 // Just a big number
+#endif
+
+template <class Transp>
+void BlynkProtocol<Transp>::sendCmd(uint8_t cmd, uint16_t id, const void* data, size_t length, const void* data2, size_t length2)
+{
+    if (0 == id) {
+        id = getNextMsgId();
+    }
+
+    if (!conn.connected() || (cmd != BLYNK_CMD_RESPONSE && cmd != BLYNK_CMD_PING && cmd != BLYNK_CMD_LOGIN && state != CONNECTED) ) {
+#ifdef BLYNK_DEBUG
+        BLYNK_LOG2(BLYNK_F("Cmd skipped:"), cmd);
+#endif
+        return;
+    }
+
+    const int full_length = (sizeof(BlynkHeader)) +
+                            (data  ? length  : 0) +
+                            (data2 ? length2 : 0);
+
+#if defined(BLYNK_SEND_ATOMIC) || defined(ESP8266) || defined(SPARK) || defined(PARTICLE) || defined(ENERGIA)
+    // Those have more RAM and like single write at a time...
+
+    uint8_t buff[full_length];
+
+    BlynkHeader* hdr = (BlynkHeader*)buff;
+    hdr->type = cmd;
+    hdr->msg_id = htons(id);
+    hdr->length = htons(length+length2);
+
+    size_t pos = sizeof(BlynkHeader);
+    if (data && length) {
+        memcpy(buff + pos, data, length);
+        pos += length;
+    }
+    if (data2 && length2) {
+        memcpy(buff + pos, data2, length2);
+    }
+
+    size_t wlen = 0;
+    while (wlen < full_length) {
+        const size_t chunk = BlynkMin(size_t(BLYNK_SEND_CHUNK), full_length - wlen);
+		BLYNK_DBG_DUMP("<", buff + wlen, chunk);
+        const size_t w = conn.write(buff + wlen, chunk);
+        delay(BLYNK_SEND_THROTTLE);
+    	if (w == 0) {
+#ifdef BLYNK_DEBUG
+            BLYNK_LOG1(BLYNK_F("Cmd error"));
+#endif
+            conn.disconnect();
+            state = CONNECTING;
+            //BlynkOnDisconnected();
+            return;
+    	}
+        wlen += w;
+    }
+
+#else
+
+    BlynkHeader hdr;
+    hdr.type = cmd;
+    hdr.msg_id = htons(id);
+    hdr.length = htons(length+length2);
+
+	BLYNK_DBG_DUMP("<", &hdr, sizeof(hdr));
+    size_t wlen = conn.write(&hdr, sizeof(hdr));
+    delay(BLYNK_SEND_THROTTLE);
+
+    if (cmd != BLYNK_CMD_RESPONSE) {
+        if (length) {
+            BLYNK_DBG_DUMP("<", data, length);
+            wlen += conn.write(data, length);
+            delay(BLYNK_SEND_THROTTLE);
+        }
+        if (length2) {
+            BLYNK_DBG_DUMP("<", data2, length2);
+            wlen += conn.write(data2, length2);
+            delay(BLYNK_SEND_THROTTLE);
+        }
+    }
+
+#endif
+
+    if (wlen != full_length) {
+#ifdef BLYNK_DEBUG
+        BLYNK_LOG4(BLYNK_F("Sent "), wlen, '/', full_length);
+#endif
+        conn.disconnect();
+        state = CONNECTING;
+        //BlynkOnDisconnected();
+        return;
+    }
+
+#if defined BLYNK_MSG_LIMIT && BLYNK_MSG_LIMIT > 0
+    const millis_time_t ts = this->getMillis();
+    BlynkAverageSample<32>(deltaCmd, ts - lastActivityOut);
+    lastActivityOut = ts;
+    //BLYNK_LOG2(BLYNK_F("Delta: "), deltaCmd);
+    if (deltaCmd < (1000/BLYNK_MSG_LIMIT)) {
+        BLYNK_LOG_TROUBLE(BLYNK_F("flood-error"));
+        conn.disconnect();
+        state = CONNECTING;
+        //BlynkOnDisconnected();
+    }
+#else
+    lastActivityOut = this->getMillis();
+#endif
+
+}
+
+template <class Transp>
+uint16_t BlynkProtocol<Transp>::getNextMsgId()
+{
+    static uint16_t last = 0;
+    if (currentMsgId != 0)
+        return currentMsgId;
+    if (++last == 0)
+        last = 1;
+    return last;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Blynk/BlynkProtocolDefs.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,126 @@
+/**
+ * @file       BlynkProtocolDefs.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Blynk protocol definitions
+ *
+ */
+
+#ifndef BlynkProtocolDefs_h
+#define BlynkProtocolDefs_h
+
+enum BlynkCmd
+{
+    BLYNK_CMD_RESPONSE       = 0,
+    BLYNK_CMD_REGISTER       = 1,
+    BLYNK_CMD_LOGIN          = 2,
+    BLYNK_CMD_SAVE_PROF      = 3,
+    BLYNK_CMD_LOAD_PROF      = 4,
+    BLYNK_CMD_GET_TOKEN      = 5,
+    BLYNK_CMD_PING           = 6,
+    BLYNK_CMD_ACTIVATE       = 7,
+    BLYNK_CMD_DEACTIVATE     = 8,
+    BLYNK_CMD_REFRESH        = 9,
+    BLYNK_CMD_GET_GRAPH_DATA = 10,
+    BLYNK_CMD_GET_GRAPH_DATA_RESPONSE = 11,
+
+    BLYNK_CMD_TWEET          = 12,
+    BLYNK_CMD_EMAIL          = 13,
+    BLYNK_CMD_NOTIFY         = 14,
+    BLYNK_CMD_BRIDGE         = 15,
+    BLYNK_CMD_HARDWARE_SYNC  = 16,
+    BLYNK_CMD_HARDWARE_INFO  = 17,
+	BLYNK_CMD_SMS            = 18,
+    BLYNK_CMD_HARDWARE       = 20,
+
+    BLYNK_CMD_CREATE_DASH    = 21,
+    BLYNK_CMD_SAVE_DASH      = 22,
+    BLYNK_CMD_DELETE_DASH    = 23,
+    BLYNK_CMD_LOAD_PROF_GZ   = 24,
+    BLYNK_CMD_SYNC           = 25,
+    BLYNK_CMD_SHARING        = 26,
+    BLYNK_CMD_ADD_PUSH_TOKEN = 27,
+
+    //sharing commands
+    BLYNK_CMD_GET_SHARED_DASH = 29,
+    BLYNK_CMD_GET_SHARE_TOKEN = 30,
+    BLYNK_CMD_REFRESH_SHARE_TOKEN = 31,
+    BLYNK_CMD_SHARE_LOGIN     = 32
+};
+
+enum BlynkStatus
+{
+    BLYNK_SUCCESS                = 200,
+    BLYNK_QUOTA_LIMIT_EXCEPTION  = 1,
+    BLYNK_ILLEGAL_COMMAND        = 2,
+    BLYNK_NOT_REGISTERED         = 3,
+    BLYNK_ALREADY_REGISTERED     = 4,
+    BLYNK_NOT_AUTHENTICATED      = 5,
+    BLYNK_NOT_ALLOWED            = 6,
+    BLYNK_NO_CONNECTION          = 7,
+    BLYNK_NO_ACTIVE_DASHBOARD    = 8,
+    BLYNK_INVALID_TOKEN          = 9,
+    BLYNK_DEVICE_WENT_OFFLINE    = 10,
+    BLYNK_ALREADY_LOGGED_IN      = 11,
+    BLYNK_GET_GRAPH_DATA_EXCEPTION = 12,
+    BLYNK_NO_DATA_EXCEPTION      = 17,
+    BLYNK_DEVICE_WENT_OFFLINE_2  = 18,
+    BLYNK_SERVER_EXCEPTION       = 19,
+
+    BLYNK_NTF_INVALID_BODY       = 13,
+    BLYNK_NTF_NOT_AUTHORIZED     = 14,
+    BLYNK_NTF_ECXEPTION          = 15,
+
+    BLYNK_TIMEOUT                = 16
+};
+
+struct BlynkHeader
+{
+    uint8_t  type;
+    uint16_t msg_id;
+    uint16_t length;
+}
+BLYNK_ATTR_PACKED;
+
+#if defined(ARDUINO) || defined(ESP8266) || defined(PARTICLE) || defined(MBED_LIBRARY_VERSION)
+    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+        #define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
+        #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
+                           ((x)<< 8 & 0x00FF0000UL) | \
+                           ((x)>> 8 & 0x0000FF00UL) | \
+                           ((x)>>24 & 0x000000FFUL) )
+        #define ntohs(x) htons(x)
+        #define ntohl(x) htonl(x)
+    #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+        #define htons(x) (x)
+        #define htonl(x) (x)
+        #define ntohs(x) (x)
+        #define ntohl(x) (x)
+    #else
+        #error byte order problem
+    #endif
+#endif
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+    #define BLYNK_HW_PM (('p' << 0) | ('m' << 8))
+    #define BLYNK_HW_DW (('d' << 0) | ('w' << 8))
+    #define BLYNK_HW_DR (('d' << 0) | ('r' << 8))
+    #define BLYNK_HW_AW (('a' << 0) | ('w' << 8))
+    #define BLYNK_HW_AR (('a' << 0) | ('r' << 8))
+    #define BLYNK_HW_VW (('v' << 0) | ('w' << 8))
+    #define BLYNK_HW_VR (('v' << 0) | ('r' << 8))
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+    #define BLYNK_HW_PM (('p' << 8) | ('m' << 0))
+    #define BLYNK_HW_DW (('d' << 8) | ('w' << 0))
+    #define BLYNK_HW_DR (('d' << 8) | ('r' << 0))
+    #define BLYNK_HW_AW (('a' << 8) | ('w' << 0))
+    #define BLYNK_HW_AR (('a' << 8) | ('r' << 0))
+    #define BLYNK_HW_VW (('v' << 8) | ('w' << 0))
+    #define BLYNK_HW_VR (('v' << 8) | ('r' << 0))
+#else
+    #error byte order problem
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BlynkApiMbed.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,194 @@
+/**
+ * @file       BlynkApiArduino.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Mar 2015
+ * @brief
+ *
+ */
+
+#ifndef BlynkApiArduino_h
+#define BlynkApiArduino_h
+
+#include <Blynk/BlynkApi.h>
+#include "mbed.h"
+
+Timer  blynk_millis_timer;
+Ticker blynk_waker;
+
+static
+void blynk_wake() {
+    //pc.puts("(...)");
+}
+/*
+static
+void delay(unsigned long ms)
+{
+    wait_ms(ms);
+}
+
+static
+unsigned long millis(void)
+{
+    return blynk_millis_timer.read_ms();
+}
+*/
+template<class Proto>
+void BlynkApi<Proto>::Init()
+{
+    blynk_waker.attach(&blynk_wake, 2.0);
+    blynk_millis_timer.start();
+}
+
+template<class Proto>
+BLYNK_FORCE_INLINE
+millis_time_t BlynkApi<Proto>::getMillis()
+{
+    return blynk_millis_timer.read_ms();
+}
+
+#ifdef BLYNK_NO_INFO
+
+template<class Proto>
+BLYNK_FORCE_INLINE
+void BlynkApi<Proto>::sendInfo() {}
+
+#else
+
+template<class Proto>
+BLYNK_FORCE_INLINE
+void BlynkApi<Proto>::sendInfo()
+{
+    static const char profile[] BLYNK_PROGMEM =
+        BLYNK_PARAM_KV("ver"    , BLYNK_VERSION)
+        BLYNK_PARAM_KV("h-beat" , TOSTRING(BLYNK_HEARTBEAT))
+        BLYNK_PARAM_KV("buff-in", TOSTRING(BLYNK_MAX_READBYTES))
+#ifdef BLYNK_INFO_DEVICE
+        BLYNK_PARAM_KV("dev"    , BLYNK_INFO_DEVICE)
+#endif
+#ifdef BLYNK_INFO_CPU
+        BLYNK_PARAM_KV("cpu"    , BLYNK_INFO_CPU)
+#endif
+#ifdef BLYNK_INFO_CONNECTION
+        BLYNK_PARAM_KV("con"    , BLYNK_INFO_CONNECTION)
+#endif
+        BLYNK_PARAM_KV("build"  , __DATE__ " " __TIME__)
+    ;
+    const size_t profile_len = sizeof(profile)-1;
+
+#ifdef BLYNK_HAS_PROGMEM
+    char mem[profile_len];
+    memcpy_P(mem, profile, profile_len);
+    static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE_INFO, 0, mem, profile_len);
+#else
+    static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE_INFO, 0, profile, profile_len);
+#endif
+    return;
+}
+
+#endif
+
+template<class Proto>
+BLYNK_FORCE_INLINE
+void BlynkApi<Proto>::processCmd(const void* buff, size_t len)
+{
+    BlynkParam param((void*)buff, len);
+    BlynkParam::iterator it = param.begin();
+    if (it >= param.end())
+        return;
+    const char* cmd = it.asStr();
+    const uint16_t cmd16 = *(uint16_t*)cmd;
+
+    if (++it >= param.end())
+        return;
+
+#if defined(analogInputToDigitalPin)
+    // Good! Analog pins can be referenced on this device by name.
+    const uint8_t pin = (it.asStr()[0] == 'A') ?
+                         analogInputToDigitalPin(atoi(it.asStr()+1)) :
+                         it.asInt();
+#else
+    const uint8_t pin = it.asInt();
+#endif
+
+    switch(cmd16) {
+
+#ifndef BLYNK_NO_BUILTIN
+
+    case BLYNK_HW_PM: {
+        while (it < param.end()) {
+            ++it;
+            if (!strcmp(it.asStr(), "in")) {
+                //pinMode(pin, INPUT);
+            } else if (!strcmp(it.asStr(), "out") || !strcmp(it.asStr(), "pwm")) {
+                //pinMode(pin, OUTPUT);
+            } else {
+#ifdef BLYNK_DEBUG
+                BLYNK_LOG4(BLYNK_F("Invalid pin "), pin, BLYNK_F(" mode "), it.asStr());
+#endif
+            }
+            ++it;
+        }
+    } break;
+    case BLYNK_HW_DR: {
+        DigitalIn p((PinName)pin);
+        char mem[16];
+        BlynkParam rsp(mem, 0, sizeof(mem));
+        rsp.add("dw");
+        rsp.add(pin);
+        rsp.add(int(p));
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, rsp.getBuffer(), rsp.getLength()-1);
+    } break;
+    case BLYNK_HW_DW: {
+        // Should be 1 parameter (value)
+        if (++it >= param.end())
+            return;
+
+        //BLYNK_LOG("digitalWrite %d -> %d", pin, it.asInt());
+        DigitalOut p((PinName)pin);
+        p = it.asInt() ? 1 : 0;
+    } break;
+    case BLYNK_HW_AR: {
+        AnalogIn p((PinName)pin);
+        char mem[16];
+        BlynkParam rsp(mem, 0, sizeof(mem));
+        rsp.add("aw");
+        rsp.add(pin);
+        rsp.add(int(p.read() * 1024));
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, rsp.getBuffer(), rsp.getLength()-1);
+    } break;
+    case BLYNK_HW_AW: {
+        // TODO: Not supported yet
+    } break;
+
+#endif
+
+    case BLYNK_HW_VR: {
+        BlynkReq req = { pin };
+        WidgetReadHandler handler = GetReadHandler(pin);
+        if (handler && (handler != BlynkWidgetRead)) {
+            handler(req);
+        } else {
+            BlynkWidgetReadDefault(req);
+        }
+    } break;
+    case BLYNK_HW_VW: {
+        ++it;
+        char* start = (char*)it.asStr();
+        BlynkParam param2(start, len - (start - (char*)buff));
+        BlynkReq req = { pin };
+        WidgetWriteHandler handler = GetWriteHandler(pin);
+        if (handler && (handler != BlynkWidgetWrite)) {
+            handler(req, param2);
+        } else {
+            BlynkWidgetWriteDefault(req, param2);
+        }
+    } break;
+    default:
+        BLYNK_LOG2(BLYNK_F("Invalid HW cmd: "), cmd);
+        static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_RESPONSE, static_cast<Proto*>(this)->currentMsgId, NULL, BLYNK_ILLEGAL_COMMAND);
+    }
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BlynkSimpleUserDefined.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,79 @@
+/**
+ * @file       BlynkSimpleUserManaged.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jun 2015
+ * @brief
+ *
+ */
+
+#ifndef BlynkSimpleUserManaged_h
+#define BlynkSimpleUserManaged_h
+
+#ifndef BLYNK_INFO_CONNECTION
+#define BLYNK_INFO_CONNECTION "custom"
+#endif
+
+#include <BlynkApiMbed.h>
+#include <Blynk/BlynkProtocol.h>
+
+extern size_t BlynkStreamRead(void* buf, size_t len);
+extern size_t BlynkStreamWrite(const void* buf, size_t len);
+
+class BlynkTransportUserDefined
+{
+public:
+    BlynkTransportUserDefined()
+        : mConn (false)
+    {}
+
+    bool connect() {
+        return mConn = true;
+    }
+
+    void disconnect() { mConn = false; }
+
+    bool connected() {
+        return mConn;
+    }
+
+    size_t read(void* buf, size_t len) {
+        return BlynkStreamRead(buf, len);
+    }
+
+    size_t write(const void* buf, size_t len) {
+        return BlynkStreamWrite(buf, len);
+    }
+
+    size_t available() {
+        return 0;
+    }
+
+private:
+    bool mConn;
+};
+
+class BlynkUserDefined
+    : public BlynkProtocol<BlynkTransportUserDefined>
+{
+    typedef BlynkProtocol<BlynkTransportUserDefined> Base;
+public:
+    BlynkUserDefined(BlynkTransportUserDefined& transp)
+        : Base(transp)
+    {}
+
+    void begin(const char* auth)
+    {
+        Base::begin(auth);
+    }
+
+private:
+};
+
+static BlynkTransportUserDefined _blynkTransport;
+BlynkUserDefined Blynk(_blynkTransport);
+
+#include <BlynkWidgets.h>
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BlynkWidgets.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,14 @@
+/**
+ * @file       BlynkWidgets.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Mar 2015
+ * @brief
+ */
+
+#include <WidgetLED.h>
+#include <WidgetLCD.h>
+#include <WidgetTerminal.h>
+#include <WidgetBridge.h>
+// Cannot auto-include WidgetSD, as it has library dependency
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WidgetBridge.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,122 @@
+/**
+ * @file       WidgetBridge.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Apr 2015
+ * @brief
+ *
+ */
+
+#ifndef WidgetBridge_h
+#define WidgetBridge_h
+
+#include <Blynk/BlynkApi.h>
+
+class WidgetBridge
+{
+public:
+    WidgetBridge(int vPin)
+        : mPin(vPin)
+    {}
+    void onWrite(BlynkReq& request, const BlynkParam& param) {}
+
+    void setAuthToken(const char* token) {
+        char mem[64];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("i");
+        cmd.add(token);
+        Blynk.sendCmd(BLYNK_CMD_BRIDGE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T>
+    void digitalWrite(const T& pin, int val) {
+        char mem[64];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("dw");
+        cmd.add(pin);
+        cmd.add(val);
+        Blynk.sendCmd(BLYNK_CMD_BRIDGE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T>
+    void analogWrite(const T& pin, int val) {
+        char mem[64];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("aw");
+        cmd.add(pin);
+        cmd.add(val);
+        Blynk.sendCmd(BLYNK_CMD_BRIDGE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T>
+    void virtualWrite(int pin, const T& data) {
+        char mem[64];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data);
+        Blynk.sendCmd(BLYNK_CMD_BRIDGE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T1, typename T2>
+    void virtualWrite(int pin, const T1& data1, const T2& data2) {
+        char mem[64];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data1);
+        cmd.add(data2);
+        Blynk.sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T1, typename T2, typename T3>
+    void virtualWrite(int pin, const T1& data1, const T2& data2, const T3& data3) {
+        char mem[64];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data1);
+        cmd.add(data2);
+        cmd.add(data3);
+        Blynk.sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    template <typename T1, typename T2, typename T3, typename T4>
+    void virtualWrite(int pin, const T1& data1, const T2& data2, const T3& data3, const T4& data4) {
+        char mem[64];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("vw");
+        cmd.add(pin);
+        cmd.add(data1);
+        cmd.add(data2);
+        cmd.add(data3);
+        cmd.add(data4);
+        Blynk.sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
+    }
+
+    void virtualWriteBinary(int pin, const void* buff, size_t len) {
+        char mem[8];
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add(mPin);
+        cmd.add("vw");
+        cmd.add(pin);
+        Blynk.sendCmd(BLYNK_CMD_BRIDGE, 0, cmd.getBuffer(), cmd.getLength(), buff, len);
+    }
+
+    void virtualWrite(int pin, const BlynkParam& param) {
+        virtualWriteBinary(pin, param.getBuffer(), param.getLength()-1);
+    }
+
+private:
+    int mPin;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WidgetLCD.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,40 @@
+/**
+ * @file       WidgetLCD.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Mar 2015
+ * @brief
+ */
+
+#ifndef WidgetLCD_h
+#define WidgetLCD_h
+
+#include <Blynk/BlynkApi.h>
+
+class WidgetLCD
+{
+public:
+    WidgetLCD(uint8_t pin) : mPin(pin) {}
+    void setVPin(int vPin) { mPin = vPin; }
+
+    void clear() {
+        Blynk.virtualWrite(mPin, "clr");
+    }
+
+    template<typename T>
+    void print(int x, int y, const T& str) {
+        char mem[64] = "";
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("p");
+        cmd.add(x);
+        cmd.add(y);
+        cmd.add(str);
+        Blynk.virtualWrite(mPin, cmd);
+    }
+
+private:
+    uint8_t mPin;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WidgetLED.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,67 @@
+/**
+ * @file       WidgetLED.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Apr 2015
+ * @brief
+ */
+
+#ifndef WidgetLED_h
+#define WidgetLED_h
+
+#include <Blynk/BlynkApi.h>
+
+class WidgetLED
+{
+public:
+	WidgetLED(uint8_t pin) : mPin(pin) {}
+    void setVPin(int vPin) { mPin = vPin; }
+
+#ifdef BLYNK_EXPERIMENTAL
+
+    void setRGB(uint8_t r, uint8_t g, uint8_t b) {
+        char mem[64] = "";
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("rgb");
+        cmd.add(r);
+        cmd.add(g);
+        cmd.add(b);
+        Blynk.virtualWrite(mPin, cmd);
+    }
+
+    void setHSV(uint8_t h, uint8_t s, uint8_t v) {
+        char mem[64] = "";
+        BlynkParam cmd(mem, 0, sizeof(mem));
+        cmd.add("hsv");
+        cmd.add(h);
+        cmd.add(s);
+        cmd.add(v);
+        Blynk.virtualWrite(mPin, cmd);
+    }
+
+#endif
+
+    uint8_t getValue() const {
+        return mValue;
+    }
+
+    void setValue(uint8_t value) {
+    	mValue = value;
+        Blynk.virtualWrite(mPin, value);
+    }
+
+    void on() {
+    	setValue(255);
+    }
+
+    void off() {
+    	setValue(0);
+    }
+
+private:
+    uint8_t mPin;
+    uint8_t mValue;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WidgetTerminal.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,81 @@
+/**
+ * @file       WidgetTerminal.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief
+ */
+
+#ifndef WidgetTerminal_h
+#define WidgetTerminal_h
+
+#if !(defined(LINUX) || defined(MBED_LIBRARY_VERSION))
+    #define BLYNK_USE_PRINT_CLASS
+#endif
+
+#include <Blynk/BlynkApi.h>
+
+#ifdef BLYNK_USE_PRINT_CLASS
+    #if !(defined(SPARK) || defined(PARTICLE) || (PLATFORM_ID==88) || defined(ARDUINO_RedBear_Duo)) // 88 -> RBL Duo
+        // On Particle this is auto-included
+        #include <Print.h>
+    #endif
+#endif
+
+class WidgetTerminal
+#ifdef BLYNK_USE_PRINT_CLASS
+    : public Print
+#endif
+{
+public:
+    WidgetTerminal(int vPin)
+        : mPin(vPin), mOutQty(0)
+    {}
+
+    virtual size_t write(uint8_t byte) {
+        mOutBuf[mOutQty++] = byte;
+        if (mOutQty >= sizeof(mOutBuf)) {
+            flush();
+        }
+        return 1;
+    }
+
+    void flush() {
+        if (mOutQty) {
+            Blynk.virtualWriteBinary(mPin, mOutBuf, mOutQty);
+            mOutQty = 0;
+        }
+    }
+
+#ifdef BLYNK_USE_PRINT_CLASS
+
+    using Print::write;
+
+    size_t write(const void* buff, size_t len) {
+        return write((char*)buff, len);
+    }
+
+#else
+
+    size_t write(const void* buff, size_t len) {
+        uint8_t* buf = (uint8_t*)buff;
+        while (len--) {
+            write(*buf++);
+        }
+        return len;
+    }
+
+    size_t write(const char* str) {
+        return write(str, strlen(str));
+    }
+
+#endif
+
+private:
+    uint8_t mPin;
+    uint8_t mOutBuf[32];
+    uint8_t mOutQty;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/BlynkDebug.cpp	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,27 @@
+/**
+ * @file       BlynkDebug.cpp
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Debug utilities for Arduino
+ */
+
+#include <Blynk/BlynkDebug.h>
+#include "mbed.h"
+
+size_t BlynkFreeRam()
+{
+    return 0;
+}
+
+void BlynkReset()
+{
+    for(;;); // To make compiler happy
+}
+
+void BlynkFatal()
+{
+    wait(10000L);
+    BlynkReset();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/BlynkFifo.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,95 @@
+/**
+ * @file       BlynkFifo.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Feb 2015
+ * @brief      FIFO implementation
+ *
+ */
+
+#ifndef BlynkFifo_h
+#define BlynkFifo_h
+
+#include <utility/BlynkUtility.h>
+
+template<typename T, unsigned SIZE>
+class BlynkFifo {
+
+    BlynkFifo(const BlynkFifo<T, SIZE> & rb);
+
+public:
+
+    BlynkFifo() : fst(0), lst(0), flag(0) {}
+    ~BlynkFifo() {}
+
+    void clear() {
+        fst = 0;
+        lst = 0;
+        flag = 0;
+    }
+
+    size_t write(const T* data, size_t n)
+    {
+        if ((n = BlynkMin(n, getFree()))) {
+            const size_t ch1 = BlynkMin(n, SIZE - lst);
+            memcpy(buffer + lst, data, ch1 * sizeof(T));
+            lst = (lst + ch1) % SIZE;
+
+            if (ch1 < n) {
+                const size_t ch2 = n - ch1;
+                memcpy(buffer + lst, data + ch1, ch2 * sizeof(T));
+                lst = (lst + ch2) % SIZE;
+            }
+
+            if (fst == lst) {
+                flag = 1;
+            }
+        }
+        return n;
+    }
+
+    size_t read(T* dest, size_t n)
+    {
+        if ((n = BlynkMin(n, getOccupied()))) {
+            flag = 0;
+
+            const size_t ch1 = BlynkMin(n, SIZE - fst);
+            memcpy(dest, buffer + fst, ch1 * sizeof(T));
+            fst = (fst + ch1) % SIZE;
+
+            if (ch1 < n) {
+                const size_t ch2 = n - ch1;
+                memcpy(dest + ch1, buffer + fst, ch2 * sizeof(T));
+                fst = (fst + ch2) % SIZE;
+            }
+        }
+        return n;
+    }
+
+    bool push(const T& data) {
+        return write(&data, 1) == 1;
+    }
+
+    size_t getOccupied() const {
+        if (lst == fst) {
+            return flag ? SIZE : 0;
+        } else if (lst > fst) {
+            return lst - fst;
+        } else {
+            return SIZE + lst - fst;
+        }
+    }
+
+    size_t getFree() const {
+        return SIZE - getOccupied();
+    }
+
+private:
+    T buffer[SIZE];
+    size_t fst;
+    size_t lst;
+    uint8_t flag;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/BlynkFifo2.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,151 @@
+/**
+ * @file       BlynkFifo.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Feb 2015
+ * @brief      FIFO implementation
+ *
+ */
+
+#ifndef BlynkFifo_h
+#define BlynkFifo_h
+
+#include <utility/BlynkUtility.h>
+
+template <class T, unsigned N>
+class BlynkFifo
+{
+public:
+    BlynkFifo()
+    {
+        clear();
+    }
+
+    void clear()
+    {
+        _r = 0;
+        _w = 0;
+    }
+
+    ~BlynkFifo(void)
+    {}
+
+    // writing thread/context API
+    //-------------------------------------------------------------
+
+    bool writeable(void)
+    {
+        return free() > 0;
+    }
+
+    int free(void)
+    {
+        int s = _r - _w;
+        if (s <= 0)
+            s += N;
+        return s - 1;
+    }
+
+    T put(const T& c)
+    {
+        int i = _w;
+        int j = i;
+        i = _inc(i);
+        while (i == _r) // = !writeable()
+            /* nothing / just wait */;
+        _b[j] = c;
+        _w = i;
+        return c;
+    }
+
+    int put(const T* p, int n, bool t = false)
+    {
+        int c = n;
+        while (c)
+        {
+            int f;
+            while ((f = free()) == 0) // wait for space
+            {
+                if (!t) return n - c; // no more space and not blocking
+                /* nothing / just wait */;
+            }
+            // check free space
+            if (c < f) f = c;
+            int w = _w;
+            int m = N - w;
+            // check wrap
+            if (f > m) f = m;
+            memcpy(&_b[w], p, f);
+            _w = _inc(w, f);
+            c -= f;
+            p += f;
+        }
+        return n - c;
+    }
+
+    // reading thread/context API
+    // --------------------------------------------------------
+
+    bool readable(void)
+    {
+        return (_r != _w);
+    }
+
+    size_t size(void)
+    {
+        int s = _w - _r;
+        if (s < 0)
+            s += N;
+        return s;
+    }
+
+    T get(void)
+    {
+        int r = _r;
+        while (r == _w) // = !readable()
+            /* nothing / just wait */;
+        T t = _b[r];
+        _r = _inc(r);
+        return t;
+    }
+
+    int get(T* p, int n, bool t = false)
+    {
+        int c = n;
+        while (c)
+        {
+            int f;
+            for (;;) // wait for data
+            {
+                f = size();
+                if (f)  break;        // free space
+                if (!t) return n - c; // no space and not blocking
+                /* nothing / just wait */;
+            }
+            // check available data
+            if (c < f) f = c;
+            int r = _r;
+            int m = N - r;
+            // check wrap
+            if (f > m) f = m;
+            memcpy(p, &_b[r], f);
+            _r = _inc(r, f);
+            c -= f;
+            p += f;
+        }
+        return n - c;
+    }
+
+private:
+    inline int _inc(int i, int n = 1)
+    {
+        return (i + n) % N;
+    }
+
+    T             _b[N];
+    volatile int  _w;
+    volatile int  _r;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/BlynkHandlers.cpp	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,147 @@
+/**
+ * @file       BlynkHandlers.cpp
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jan 2015
+ * @brief      Virtual pin utilities
+ */
+
+#include <Blynk/BlynkConfig.h>
+#include <Blynk/BlynkHandlers.h>
+#include <Blynk/BlynkDebug.h>
+
+void BlynkNoOpCbk()
+{}
+
+void BlynkWidgetRead(BlynkReq& request)
+{
+    BLYNK_LOG2(BLYNK_F("No handler for reading from pin "), request.pin);
+}
+
+void BlynkWidgetWrite(BlynkReq& request, const BlynkParam& param)
+{
+    BLYNK_LOG2(BLYNK_F("No handler for writing to pin "), request.pin);
+}
+
+#define BLYNK_ON_READ_IMPL(pin)  void BlynkWidgetRead  ## pin (BlynkReq& req) \
+          __attribute__((weak, alias("BlynkWidgetRead")))
+
+#define BLYNK_ON_WRITE_IMPL(pin) void BlynkWidgetWrite ## pin (BlynkReq& req, const BlynkParam& param) \
+          __attribute__((weak, alias("BlynkWidgetWrite")))
+
+BLYNK_CONNECTED() __attribute__((weak, alias("BlynkNoOpCbk")));
+BLYNK_DISCONNECTED() __attribute__((weak, alias("BlynkNoOpCbk")));
+
+BLYNK_ON_READ_IMPL(Default);
+BLYNK_ON_WRITE_IMPL(Default);
+
+BLYNK_ON_READ_IMPL(0 );
+BLYNK_ON_READ_IMPL(1 );
+BLYNK_ON_READ_IMPL(2 );
+BLYNK_ON_READ_IMPL(3 );
+BLYNK_ON_READ_IMPL(4 );
+BLYNK_ON_READ_IMPL(5 );
+BLYNK_ON_READ_IMPL(6 );
+BLYNK_ON_READ_IMPL(7 );
+BLYNK_ON_READ_IMPL(8 );
+BLYNK_ON_READ_IMPL(9 );
+BLYNK_ON_READ_IMPL(10);
+BLYNK_ON_READ_IMPL(11);
+BLYNK_ON_READ_IMPL(12);
+BLYNK_ON_READ_IMPL(13);
+BLYNK_ON_READ_IMPL(14);
+BLYNK_ON_READ_IMPL(15);
+BLYNK_ON_READ_IMPL(16);
+BLYNK_ON_READ_IMPL(17);
+BLYNK_ON_READ_IMPL(18);
+BLYNK_ON_READ_IMPL(19);
+BLYNK_ON_READ_IMPL(20);
+BLYNK_ON_READ_IMPL(21);
+BLYNK_ON_READ_IMPL(22);
+BLYNK_ON_READ_IMPL(23);
+BLYNK_ON_READ_IMPL(24);
+BLYNK_ON_READ_IMPL(25);
+BLYNK_ON_READ_IMPL(26);
+BLYNK_ON_READ_IMPL(27);
+BLYNK_ON_READ_IMPL(28);
+BLYNK_ON_READ_IMPL(29);
+BLYNK_ON_READ_IMPL(30);
+BLYNK_ON_READ_IMPL(31);
+
+BLYNK_ON_WRITE_IMPL(0 );
+BLYNK_ON_WRITE_IMPL(1 );
+BLYNK_ON_WRITE_IMPL(2 );
+BLYNK_ON_WRITE_IMPL(3 );
+BLYNK_ON_WRITE_IMPL(4 );
+BLYNK_ON_WRITE_IMPL(5 );
+BLYNK_ON_WRITE_IMPL(6 );
+BLYNK_ON_WRITE_IMPL(7 );
+BLYNK_ON_WRITE_IMPL(8 );
+BLYNK_ON_WRITE_IMPL(9 );
+BLYNK_ON_WRITE_IMPL(10);
+BLYNK_ON_WRITE_IMPL(11);
+BLYNK_ON_WRITE_IMPL(12);
+BLYNK_ON_WRITE_IMPL(13);
+BLYNK_ON_WRITE_IMPL(14);
+BLYNK_ON_WRITE_IMPL(15);
+BLYNK_ON_WRITE_IMPL(16);
+BLYNK_ON_WRITE_IMPL(17);
+BLYNK_ON_WRITE_IMPL(18);
+BLYNK_ON_WRITE_IMPL(19);
+BLYNK_ON_WRITE_IMPL(20);
+BLYNK_ON_WRITE_IMPL(21);
+BLYNK_ON_WRITE_IMPL(22);
+BLYNK_ON_WRITE_IMPL(23);
+BLYNK_ON_WRITE_IMPL(24);
+BLYNK_ON_WRITE_IMPL(25);
+BLYNK_ON_WRITE_IMPL(26);
+BLYNK_ON_WRITE_IMPL(27);
+BLYNK_ON_WRITE_IMPL(28);
+BLYNK_ON_WRITE_IMPL(29);
+BLYNK_ON_WRITE_IMPL(30);
+BLYNK_ON_WRITE_IMPL(31);
+
+static const WidgetReadHandler BlynkReadHandlerVector[] BLYNK_PROGMEM = {
+    BlynkWidgetRead0,   BlynkWidgetRead1,   BlynkWidgetRead2,   BlynkWidgetRead3,
+    BlynkWidgetRead4,   BlynkWidgetRead5,   BlynkWidgetRead6,   BlynkWidgetRead7,
+    BlynkWidgetRead8,   BlynkWidgetRead9,   BlynkWidgetRead10,  BlynkWidgetRead11,
+    BlynkWidgetRead12,  BlynkWidgetRead13,  BlynkWidgetRead14,  BlynkWidgetRead15,
+    BlynkWidgetRead16,  BlynkWidgetRead17,  BlynkWidgetRead18,  BlynkWidgetRead19,
+    BlynkWidgetRead20,  BlynkWidgetRead21,  BlynkWidgetRead22,  BlynkWidgetRead23,
+    BlynkWidgetRead24,  BlynkWidgetRead25,  BlynkWidgetRead26,  BlynkWidgetRead27,
+    BlynkWidgetRead28,  BlynkWidgetRead29,  BlynkWidgetRead30,  BlynkWidgetRead31,
+};
+
+static const WidgetWriteHandler BlynkWriteHandlerVector[] BLYNK_PROGMEM = {
+    BlynkWidgetWrite0,  BlynkWidgetWrite1,  BlynkWidgetWrite2,  BlynkWidgetWrite3,
+    BlynkWidgetWrite4,  BlynkWidgetWrite5,  BlynkWidgetWrite6,  BlynkWidgetWrite7,
+    BlynkWidgetWrite8,  BlynkWidgetWrite9,  BlynkWidgetWrite10, BlynkWidgetWrite11,
+    BlynkWidgetWrite12, BlynkWidgetWrite13, BlynkWidgetWrite14, BlynkWidgetWrite15,
+    BlynkWidgetWrite16, BlynkWidgetWrite17, BlynkWidgetWrite18, BlynkWidgetWrite19,
+    BlynkWidgetWrite20, BlynkWidgetWrite21, BlynkWidgetWrite22, BlynkWidgetWrite23,
+    BlynkWidgetWrite24, BlynkWidgetWrite25, BlynkWidgetWrite26, BlynkWidgetWrite27,
+    BlynkWidgetWrite28, BlynkWidgetWrite29, BlynkWidgetWrite30, BlynkWidgetWrite31,
+};
+
+WidgetReadHandler GetReadHandler(uint8_t pin)
+{
+    if (pin >= COUNT_OF(BlynkReadHandlerVector))
+        return NULL;
+#ifdef BLYNK_HAS_PROGMEM
+    return (WidgetReadHandler)pgm_read_word(&BlynkReadHandlerVector[pin]);
+#else
+    return BlynkReadHandlerVector[pin];
+#endif
+}
+
+WidgetWriteHandler GetWriteHandler(uint8_t pin)
+{
+    if (pin >= COUNT_OF(BlynkWriteHandlerVector))
+        return NULL;
+#ifdef BLYNK_HAS_PROGMEM
+    return (WidgetWriteHandler)pgm_read_word(&BlynkWriteHandlerVector[pin]);
+#else
+    return BlynkWriteHandlerVector[pin];
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utility/BlynkUtility.h	Sat May 07 08:02:50 2016 +0000
@@ -0,0 +1,34 @@
+/**
+ * @file       BlynkUtility.h
+ * @author     Volodymyr Shymanskyy
+ * @license    This project is released under the MIT License (MIT)
+ * @copyright  Copyright (c) 2015 Volodymyr Shymanskyy
+ * @date       Jun 2015
+ * @brief      Utility functions
+ *
+ */
+
+#ifndef BlynkUtility_h
+#define BlynkUtility_h
+
+template<class T>
+const T& BlynkMin(const T& a, const T& b)
+{
+    return (b < a) ? b : a;
+}
+
+template<class T>
+const T& BlynkMax(const T& a, const T& b)
+{
+    return (b < a) ? a : b;
+}
+
+template <unsigned WSIZE, typename T>
+void BlynkAverageSample (T& avg, const T& input) {
+    avg -= avg/WSIZE;
+    const T add = input/WSIZE;
+    // Fix for shorter delays
+    avg += (add > 0) ? add : -1;
+}
+
+#endif