├── LICENSE ├── README.md ├── examples ├── 01_Particle │ └── 01_Particle.ino └── 02_Particle_Electron │ └── 02_Particle_Electron.ino ├── library.properties ├── src ├── Adapters │ ├── BlynkParticle.h │ ├── BlynkParticleBearSSL.h │ └── BlynkSerial.h ├── Blynk │ ├── BlynkApi.h │ ├── BlynkConfig.h │ ├── BlynkConsole.h │ ├── BlynkDateTime.h │ ├── BlynkDebug.h │ ├── BlynkDetectDevice.h │ ├── BlynkEveryN.h │ ├── BlynkHandlers.h │ ├── BlynkHelpers.h │ ├── BlynkParam.h │ ├── BlynkProtocol.h │ ├── BlynkProtocolDefs.h │ ├── BlynkTemplates.h │ ├── BlynkTimer.h │ ├── BlynkUtility.h │ └── BlynkWidgetBase.h ├── BlynkApiParticle.h ├── BlynkMultiClient.h ├── BlynkSimpleParticle.h ├── BlynkSimpleParticleSSL.h ├── BlynkSimpleSerialBLE.h ├── BlynkSimpleStream.h ├── BlynkWidgets.h ├── WidgetLCD.h ├── WidgetLED.h ├── WidgetMap.h ├── WidgetTerminal.h ├── WidgetTimeInput.h ├── blynk.cpp ├── blynk.h └── utility │ ├── BlynkDateTime.h │ ├── BlynkDebug.cpp │ ├── BlynkFifo.h │ ├── BlynkHandlers.cpp │ ├── BlynkHelpers.cpp │ ├── BlynkStreamMulti.h │ ├── BlynkStreamNull.h │ ├── BlynkTimeUtils.cpp │ ├── BlynkTimer.cpp │ └── BlynkUtility.h └── verification.txt /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015 Volodymyr Shymanskyy 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine) 2 | 3 | # Blynk C++ Library [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Build%20your%20IoT%20App%20in%20minutes,%20right%20on%20your%20smartphone!&url=https://github.com/blynkkk/blynk-library&via=blynk_app&hashtags=IoT,iOS,Android,Arduino,ESP8266,ESP32,RaspberryPi) 4 | 5 | [![GitHub version](https://img.shields.io/github/release/blynkkk/blynk-library.svg)](https://github.com/blynkkk/blynk-library/releases/latest) 6 | [![GitHub download](https://img.shields.io/github/downloads/blynkkk/blynk-library/total.svg)](https://github.com/blynkkk/blynk-library/releases/latest) 7 | [![GitHub stars](https://img.shields.io/github/stars/blynkkk/blynk-library.svg)](https://github.com/blynkkk/blynk-library/stargazers) 8 | [![GitHub issues](https://img.shields.io/github/issues/blynkkk/blynk-library.svg)](https://github.com/blynkkk/blynk-library/issues) 9 | [![Build Status](https://img.shields.io/travis/blynkkk/blynk-library.svg)](https://travis-ci.org/blynkkk/blynk-library) 10 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/blynkkk/blynk-library/blob/master/LICENSE) 11 | 12 | If you like **Blynk** - give it a star, or fork it and contribute! 13 | [![GitHub stars](https://img.shields.io/github/stars/blynkkk/blynk-library.svg?style=social&label=Star)](https://github.com/blynkkk/blynk-library/stargazers) 14 | [![GitHub forks](https://img.shields.io/github/forks/blynkkk/blynk-library.svg?style=social&label=Fork)](https://github.com/blynkkk/blynk-library/network) 15 | __________ 16 | 17 | ### Blynk is a unique IoT platform for connecting any hardware to the cloud, designing apps to control them, and managing your deployed products at scale. 18 | 19 | - With Blynk Library you can connect **over 400 hardware models** (including ESP8266, ESP32, NodeMCU, all Arduinos, Raspberry Pi, Particle, Texas Instruments, etc.) to the Blynk Cloud. 20 | 21 | - With Blynk apps for **iOS** and **Android** apps you can easily drag-n-drop graphic interfaces for any DIY or commercial project. It's a pure WYSIWG experience: no coding on iOS or Android required. 22 | 23 | - Hardware can connect to Blynk Cloud over the Internet using hardware connectivity available on your board (like ESP32), or with the use of various shields (Ethernet, WiFi, GSM, LTE, etc). Blynk Cloud is available for every user of Blynk **for free**. 24 | 25 | ![Blynk Banner](https://github.com/blynkkk/blynkkk.github.io/raw/master/images/GithubBanner.jpg) 26 | 27 | ## Downloads 28 | 29 | **Blynk [Arduino Library](https://github.com/blynkkk/blynk-library/releases/latest)** 30 | 31 | **Blynk Mobile App: 32 | [ Google Play](https://play.google.com/store/apps/details?id=cloud.blynk) | 33 | [ App Store](https://apps.apple.com/us/app/blynk-iot/id1559317868)** 34 | 35 | ## Quickstart: Particle Gen2 / Gen3 36 | 37 | * Download the Blynk app ([App Store](https://apps.apple.com/us/app/blynk-iot/id1559317868), [Google Play](https://play.google.com/store/apps/details?id=cloud.blynk)) 38 | * Get the Auth Token from the app 39 | * Import this library to Particle Build IDE. 40 | * Update Auth Token in the example sketch and upload it to your device 41 | 42 | ## Documentation and other helpful links 43 | 44 | [The list of supported hardware](https://docs.blynk.io/en/blynk.edgent-firmware-api/supported-boards) - supported boards, Ethernet, WiFi, Cellular... 45 | [Full Blynk Documentation](https://docs.blynk.io) - a complete guide on Blynk features 46 | [Community (Forum)](http://community.blynk.cc) - join a 500,000 Blynk community to ask questions and share ideas 47 | [Code Examples Browser](http://examples.blynk.cc) - browse examples to explore Blynk possibilities 48 | [Official Website](https://blynk.io) 49 | 50 | **Social Media:** 51 | 52 | [Facebook](https://www.fb.com/blynkapp) | 53 | [Twitter](https://twitter.com/blynk_app) | 54 | [Youtube](https://www.youtube.com/blynk) | 55 | [Instagram](https://www.instagram.com/blynk.iot/) | 56 | [LinkedIn](https://www.linkedin.com/company/b-l-y-n-k/) 57 | 58 | ## Blynk libraries for other platforms 59 | * [Python, MicroPython](https://github.com/blynkkk/lib-python) 60 | 61 | ## Libraries by community 62 | * [Python, MicroPython](https://github.com/vshymanskyy/blynk-library-python) 63 | * [Particle](https://github.com/vshymanskyy/blynk-library-particle) 64 | * [Lua, OpenWrt, NodeMCU](https://github.com/vshymanskyy/blynk-library-lua) 65 | * [OpenWrt packages](https://github.com/vshymanskyy/blynk-library-openwrt) 66 | * [MBED](https://developer.mbed.org/users/vshymanskyy/code/Blynk/) 67 | * [Node-RED for Blynk IoT](https://flows.nodered.org/node/node-red-contrib-blynk-iot) 68 | 69 | ## Contributing 70 | We accept contributions from our community: stability bugfixes, new hardware support, or any other improvements. 71 | [Here](https://github.com/blynkkk/blynk-library/labels/help%20wanted) is a list of what you could help with. 72 | 73 | ### License 74 | This project is released under The MIT License (MIT) 75 | -------------------------------------------------------------------------------- /examples/01_Particle/01_Particle.ino: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | Blynk is a platform with iOS and Android apps to control 3 | Arduino, Raspberry Pi and the likes over the Internet. 4 | You can easily build graphic interfaces for all your 5 | projects by simply dragging and dropping widgets. 6 | 7 | Downloads, docs, tutorials: http://www.blynk.cc 8 | Sketch generator: http://examples.blynk.cc 9 | Blynk community: http://community.blynk.cc 10 | Follow us: http://www.fb.com/blynkapp 11 | http://twitter.com/blynk_app 12 | 13 | Blynk library is licensed under MIT license 14 | This example code is in public domain. 15 | 16 | ************************************************************* 17 | 18 | No coding required for direct digital/analog pin operations! 19 | 20 | *************************************************************/ 21 | 22 | #define BLYNK_PRINT Serial // Set serial output for debug prints 23 | //#define BLYNK_DEBUG // Uncomment this to see detailed prints 24 | 25 | /* Fill in information from Blynk Device Info here */ 26 | //#define BLYNK_TEMPLATE_ID "TMPxxxxxx" 27 | //#define BLYNK_TEMPLATE_NAME "Device" 28 | //#define BLYNK_AUTH_TOKEN "YourAuthToken" 29 | 30 | #include 31 | 32 | // Attach a Button widget (mode: Switch) to the Digital pin 7 - and control the built-in blue led. 33 | // Attach a Graph widget to Analog pin 1 34 | // Attach a Gauge widget to Analog pin 2 35 | 36 | void setup() 37 | { 38 | Serial.begin(9600); 39 | delay(5000); // Allow board to settle 40 | 41 | Blynk.begin(BLYNK_AUTH_TOKEN); 42 | } 43 | 44 | // Attach a Button widget (mode: Push) to the Virtual pin 1 - and send sweet tweets! 45 | BLYNK_WRITE(V1) { 46 | if (param.asInt() == 1) { // On button down... 47 | // Pushing notification to the app! 48 | // Note: 49 | // We allow 1 notification per minute for now. 50 | Blynk.logEvent("", "You pressed the button and I know it ;)"); 51 | } 52 | } 53 | 54 | // Attach a ZeRGBa widget (mode: Merge) to the Virtual pin 2 - and control the built-in RGB led! 55 | BLYNK_WRITE(V2) { 56 | int r = param[0].asInt(); 57 | int g = param[1].asInt(); 58 | int b = param[2].asInt(); 59 | if (r > 0 || g > 0 || b > 0) { 60 | RGB.control(true); 61 | RGB.color(r, g, b); 62 | } else { 63 | RGB.control(false); 64 | } 65 | } 66 | 67 | void loop() 68 | { 69 | Blynk.run(); 70 | } 71 | -------------------------------------------------------------------------------- /examples/02_Particle_Electron/02_Particle_Electron.ino: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | Blynk is a platform with iOS and Android apps to control 3 | Arduino, Raspberry Pi and the likes over the Internet. 4 | You can easily build graphic interfaces for all your 5 | projects by simply dragging and dropping widgets. 6 | 7 | Downloads, docs, tutorials: http://www.blynk.cc 8 | Sketch generator: http://examples.blynk.cc 9 | Blynk community: http://community.blynk.cc 10 | Follow us: http://www.fb.com/blynkapp 11 | http://twitter.com/blynk_app 12 | 13 | Blynk library is licensed under MIT license 14 | This example code is in public domain. 15 | 16 | ************************************************************* 17 | 18 | No coding required for direct digital/analog pin operations! 19 | 20 | *************************************************************/ 21 | 22 | #define BLYNK_PRINT Serial // Set serial output for debug prints 23 | //#define BLYNK_DEBUG // Uncomment this to see detailed prints 24 | 25 | /* Fill in information from Blynk Device Info here */ 26 | //#define BLYNK_TEMPLATE_ID "TMPxxxxxx" 27 | //#define BLYNK_TEMPLATE_NAME "Device" 28 | //#define BLYNK_AUTH_TOKEN "YourAuthToken" 29 | 30 | // Uncomment this, if you want to set network credentials 31 | //#include "cellular_hal.h" 32 | //STARTUP(cellular_credentials_set("broadband", "", "", NULL)); 33 | 34 | // Run "ping blynk-cloud.com", and set Blynk IP to the shown address 35 | #define BLYNK_IP IPAddress(45,55,130,102) 36 | 37 | // Set Blynk hertbeat interval. 38 | // Each heartbeat uses ~90 bytes of data. 39 | #define BLYNK_HEARTBEAT 60 40 | 41 | // Set Particle keep-alive ping interval. 42 | // Each ping uses 121 bytes of data. 43 | #define PARTICLE_KEEPALIVE 20 44 | 45 | #include 46 | 47 | void setup() { 48 | Serial.begin(9600); 49 | Particle.keepAlive(PARTICLE_KEEPALIVE); 50 | Blynk.begin(BLYNK_AUTH_TOKEN, BLYNK_IP); 51 | } 52 | 53 | void loop() { 54 | Blynk.run(); 55 | } 56 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=blynk 2 | version=1.3.2 3 | author=Volodymyr Shymanskyy 4 | license=MIT 5 | maintainer=Volodymyr Shymanskyy 6 | sentence=Build a smartphone app for your project in minutes! 7 | category=Communication 8 | url=https://blynk.io 9 | repository=https://github.com/vshymanskyy/blynk-library-particle.git 10 | architectures=* 11 | includes=Blynk.h 12 | -------------------------------------------------------------------------------- /src/Adapters/BlynkParticle.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkParticle.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Mar 2015 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkParticle_h 12 | #define BlynkParticle_h 13 | 14 | #include "BlynkApiParticle.h" 15 | #include "Blynk/BlynkProtocol.h" 16 | 17 | class BlynkTransportParticle 18 | { 19 | public: 20 | BlynkTransportParticle() 21 | : domain(NULL), port(0), actual_port(0) 22 | {} 23 | 24 | void begin(IPAddress a, uint16_t p) { 25 | domain = NULL; 26 | port = p; 27 | addr = a; 28 | } 29 | 30 | void begin(const char* d, uint16_t p) { 31 | domain = d; 32 | port = p; 33 | } 34 | 35 | bool _connectToPort(uint16_t p) { 36 | bool isConn = false; 37 | if (domain) { 38 | BLYNK_LOG4(BLYNK_F("Connecting to "), domain, ':', p); 39 | isConn = (1 == client.connect(domain, p)); 40 | } else { 41 | BLYNK_LOG_IP("Connecting to ", addr); 42 | isConn = (1 == client.connect(addr, p)); 43 | } 44 | actual_port = isConn ? p : 0; 45 | return isConn; 46 | } 47 | 48 | bool connect() { 49 | bool isConn = _connectToPort(port); 50 | if (!isConn) { 51 | // If port is 80 or 8080, try an alternative port 52 | if (port == 80) { 53 | isConn = _connectToPort(8080); 54 | } else if (port == 8080) { 55 | isConn = _connectToPort(80); 56 | } 57 | } 58 | return isConn; 59 | } 60 | 61 | uint16_t getActualPort() const { 62 | return actual_port; 63 | } 64 | 65 | void disconnect() { client.stop(); } 66 | 67 | size_t read(void* buf, size_t len) { 68 | return client.readBytes((char*)buf, len); 69 | } 70 | 71 | size_t write(const void* buf, size_t len) { 72 | return client.write((const uint8_t*)buf, len); 73 | } 74 | 75 | void flush() { client.flush(); } 76 | bool connected() { return client.connected(); } 77 | int available() { return client.available(); } 78 | 79 | private: 80 | TCPClient client; 81 | IPAddress addr; 82 | const char* domain; 83 | uint16_t port; 84 | uint16_t actual_port; 85 | }; 86 | 87 | class BlynkParticle 88 | : public BlynkProtocol 89 | { 90 | typedef BlynkProtocol Base; 91 | public: 92 | BlynkParticle(BlynkTransportParticle& transp) 93 | : Base(transp) 94 | {} 95 | 96 | void config(const char* auth, 97 | const char* domain = BLYNK_DEFAULT_DOMAIN, 98 | uint16_t port = BLYNK_DEFAULT_PORT) 99 | { 100 | Base::begin(auth); 101 | this->conn.begin(domain, port); 102 | } 103 | 104 | void config(const char* auth, 105 | IPAddress addr, 106 | uint16_t port = BLYNK_DEFAULT_PORT) 107 | { 108 | Base::begin(auth); 109 | this->conn.begin(addr, port); 110 | } 111 | 112 | void begin( const char* auth, 113 | const char* domain = BLYNK_DEFAULT_DOMAIN, 114 | uint16_t port = BLYNK_DEFAULT_PORT) 115 | { 116 | BlynkDelay(3000); // Give the board time to settle 117 | config(auth, domain, port); 118 | while(this->connect() != true) {} 119 | } 120 | 121 | void begin( const char* auth, 122 | IPAddress addr, 123 | uint16_t port = BLYNK_DEFAULT_PORT) 124 | { 125 | BlynkDelay(3000); // Give the board time to settle 126 | config(auth, addr, port); 127 | while(this->connect() != true) {} 128 | } 129 | private: 130 | 131 | }; 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /src/Adapters/BlynkParticleBearSSL.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkParticleBearSSL.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2022 Volodymyr Shymanskyy 6 | * @date Mar 2022 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkParticleBearSSL_h 12 | #define BlynkParticleBearSSL_h 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | class BlynkTransportParticle 20 | { 21 | public: 22 | BlynkTransportParticle() 23 | : client(tcpclient), domain(NULL), port(0) 24 | { } 25 | 26 | static 27 | unsigned long getTime() { 28 | return 1654280000; // TODO 29 | } 30 | 31 | void begin(IPAddress a, uint16_t p) { 32 | domain = NULL; 33 | port = p; 34 | addr = a; 35 | } 36 | 37 | void begin(const char* d, uint16_t p) { 38 | domain = d; 39 | port = p; 40 | } 41 | 42 | bool connect() { 43 | ArduinoBearSSL.onGetTime(getTime); 44 | if (domain) { 45 | BLYNK_LOG4(BLYNK_F("Connecting to "), domain, ':', port); 46 | if (client.connect(domain, port)) { 47 | BLYNK_LOG("Certificate OK"); 48 | return true; 49 | } else { 50 | BLYNK_LOG("Connection failed"); 51 | } 52 | } else { 53 | BLYNK_LOG_IP("Connecting to ", addr); 54 | //return (1 == client.connect(addr, port)); 55 | } 56 | return 0; 57 | } 58 | 59 | void disconnect() { client.stop(); } 60 | 61 | size_t read(void* buf, size_t len) { 62 | return client.readBytes((char*)buf, len); 63 | } 64 | 65 | size_t write(const void* buf, size_t len) { 66 | return client.write((const uint8_t*)buf, len); 67 | } 68 | 69 | void flush() { client.flush(); } 70 | bool connected() { return client.connected(); } 71 | int available() { return client.available(); } 72 | 73 | private: 74 | TCPClient tcpclient; 75 | BearSSLClient client; 76 | IPAddress addr; 77 | const char* domain; 78 | uint16_t port; 79 | }; 80 | 81 | class BlynkParticle 82 | : public BlynkProtocol 83 | { 84 | typedef BlynkProtocol Base; 85 | public: 86 | BlynkParticle(BlynkTransportParticle& transp) 87 | : Base(transp) 88 | {} 89 | 90 | void config(const char* auth, 91 | const char* domain = BLYNK_DEFAULT_DOMAIN, 92 | uint16_t port = BLYNK_DEFAULT_PORT) 93 | { 94 | Base::begin(auth); 95 | this->conn.begin(domain, port); 96 | } 97 | 98 | void config(const char* auth, 99 | IPAddress addr, 100 | uint16_t port = BLYNK_DEFAULT_PORT) 101 | { 102 | Base::begin(auth); 103 | this->conn.begin(addr, port); 104 | } 105 | 106 | void begin( const char* auth, 107 | const char* domain = BLYNK_DEFAULT_DOMAIN, 108 | uint16_t port = BLYNK_DEFAULT_PORT) 109 | { 110 | BlynkDelay(3000); // Give the board time to settle 111 | config(auth, domain, port); 112 | while(this->connect() != true) {} 113 | } 114 | 115 | void begin( const char* auth, 116 | IPAddress addr, 117 | uint16_t port = BLYNK_DEFAULT_PORT) 118 | { 119 | BlynkDelay(3000); // Give the board time to settle 120 | config(auth, addr, port); 121 | while(this->connect() != true) {} 122 | } 123 | private: 124 | 125 | }; 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /src/Adapters/BlynkSerial.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkSerial.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkStream_h 12 | #define BlynkStream_h 13 | 14 | #ifndef BLYNK_INFO_CONNECTION 15 | #define BLYNK_INFO_CONNECTION "Serial" 16 | #endif 17 | 18 | #ifdef PARTICLE 19 | #include 20 | #else 21 | #include 22 | #endif 23 | #include 24 | 25 | class BlynkTransportStream 26 | { 27 | public: 28 | BlynkTransportStream() 29 | : stream(NULL), conn(0) 30 | {} 31 | 32 | // IP redirect not available 33 | void begin(char BLYNK_UNUSED *h, uint16_t BLYNK_UNUSED p) {} 34 | 35 | void begin(Stream& s) { 36 | stream = &s; 37 | } 38 | 39 | bool connect() { 40 | BLYNK_LOG1(BLYNK_F("Connecting...")); 41 | stream->flush(); 42 | return conn = true; 43 | } 44 | void disconnect() { conn = false; } 45 | 46 | size_t read(void* buf, size_t len) { 47 | char* beg = (char*)buf; 48 | char* end = beg + len; 49 | millis_time_t startMillis = BlynkMillis(); 50 | while ((beg < end) && (BlynkMillis() - startMillis < BLYNK_TIMEOUT_MS)) { 51 | int c = stream->read(); 52 | if (c < 0) 53 | continue; 54 | *beg++ = (char)c; 55 | } 56 | return beg-(char*)buf; 57 | } 58 | size_t write(const void* buf, size_t len) { 59 | stream->write((const uint8_t*)buf, len); 60 | return len; 61 | } 62 | 63 | bool connected() { return conn; } 64 | int available() { return stream->available(); } 65 | 66 | protected: 67 | Stream* stream; 68 | bool conn; 69 | }; 70 | 71 | class BlynkStream 72 | : public BlynkProtocol 73 | { 74 | typedef BlynkProtocol Base; 75 | public: 76 | BlynkStream(BlynkTransportStream& transp) 77 | : Base(transp) 78 | {} 79 | 80 | void config(Stream& stream, 81 | const char* auth) 82 | { 83 | Base::begin(auth); 84 | this->conn.begin(stream); 85 | } 86 | 87 | void begin(Stream& stream, const char* auth) { 88 | config(stream, auth); 89 | while(this->connect() != true) {} 90 | } 91 | }; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/Blynk/BlynkApi.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkApi.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief High-level functions 8 | * 9 | */ 10 | 11 | #ifndef BlynkApi_h 12 | #define BlynkApi_h 13 | 14 | // back-compat 15 | 16 | #ifdef BOARD_FIRMWARE_TYPE 17 | #define BLYNK_FIRMWARE_TYPE BOARD_FIRMWARE_TYPE 18 | #endif 19 | 20 | #ifdef BOARD_FIRMWARE_VERSION 21 | #define BLYNK_FIRMWARE_VERSION BOARD_FIRMWARE_VERSION 22 | #endif 23 | 24 | #ifdef BOARD_TEMPLATE_ID 25 | #define BLYNK_TEMPLATE_ID BOARD_TEMPLATE_ID 26 | #endif 27 | 28 | // end of back-compat 29 | 30 | #if !defined(BLYNK_FIRMWARE_TYPE) && defined(BLYNK_TEMPLATE_ID) 31 | #define BLYNK_FIRMWARE_TYPE BLYNK_TEMPLATE_ID 32 | #endif 33 | 34 | #if !defined(BLYNK_FIRMWARE_VERSION) 35 | #define BLYNK_FIRMWARE_VERSION "0.0.0" 36 | #endif 37 | 38 | #if !defined(BLYNK_TEMPLATE_ID) || !defined(BLYNK_TEMPLATE_NAME) 39 | #error "Please specify your BLYNK_TEMPLATE_ID and BLYNK_TEMPLATE_NAME" 40 | #endif 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #if defined(BLYNK_EXPERIMENTAL) 50 | #include 51 | #endif 52 | 53 | /** 54 | * Represents high-level functions of Blynk 55 | */ 56 | template 57 | class BlynkApi 58 | { 59 | public: 60 | BlynkApi() 61 | : groupState(GROUP_NONE) 62 | , groupTs(0) 63 | { 64 | } 65 | 66 | #ifdef DOXYGEN // These API here are only for the documentation 67 | 68 | /** 69 | * Connects to the server. 70 | * Blocks until connected or timeout happens. 71 | * May take less or more then timeout value. 72 | * 73 | * @param timeout Connection timeout 74 | * @returns True if connected to the server 75 | */ 76 | bool connect(unsigned long timeout = BLYNK_TIMEOUT_MS*3); 77 | 78 | /** 79 | * Disconnects from the server. 80 | * It will not try to reconnect, until connect() is called 81 | */ 82 | void disconnect(); 83 | 84 | /** 85 | * @returns True if connected to the server 86 | */ 87 | bool connected(); 88 | 89 | /** 90 | * Performs Blynk-related housekeeping 91 | * and processes incoming commands 92 | * 93 | * @param available True if there is incoming data to process 94 | * Only used when user manages connection manually. 95 | */ 96 | bool run(bool available = false); 97 | 98 | #endif // DOXYGEN 99 | 100 | /** 101 | * Sends value to a Virtual Pin 102 | * 103 | * @param pin Virtual Pin number 104 | * @param data Value to be sent 105 | */ 106 | template 107 | void virtualWrite(int pin, Args... values) { 108 | char mem[BLYNK_MAX_SENDBYTES]; 109 | BlynkParam cmd(mem, 0, sizeof(mem)); 110 | cmd.add("vw"); 111 | cmd.add(pin); 112 | cmd.add_multi(values...); 113 | static_cast(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1); 114 | } 115 | 116 | /** 117 | * Sends buffer to a Virtual Pin 118 | * 119 | * @param pin Virtual Pin number 120 | * @param buff Data buffer 121 | * @param len Length of data 122 | */ 123 | void virtualWriteBinary(int pin, const void* buff, size_t len) { 124 | char mem[8]; 125 | BlynkParam cmd(mem, 0, sizeof(mem)); 126 | cmd.add("vw"); 127 | cmd.add(pin); 128 | static_cast(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength(), buff, len); 129 | } 130 | 131 | /** 132 | * Sends BlynkParam to a Virtual Pin 133 | * 134 | * @param pin Virtual Pin number 135 | * @param param 136 | */ 137 | void virtualWrite(int pin, const BlynkParam& param) { 138 | virtualWriteBinary(pin, param.getBuffer(), param.getLength()-1); 139 | } 140 | 141 | void virtualWrite(int pin, const BlynkParamAllocated& param) { 142 | virtualWriteBinary(pin, param.getBuffer(), param.getLength()-1); 143 | } 144 | 145 | /** 146 | * Command grouping 147 | */ 148 | void beginGroup() { 149 | if (GROUP_STARTED != groupState) { 150 | groupState = GROUP_PENDING; 151 | groupTs = 0; 152 | } 153 | } 154 | 155 | void beginGroup(uint64_t timestamp) { 156 | if (GROUP_STARTED != groupState) { 157 | groupState = GROUP_PENDING; 158 | groupTs = timestamp; 159 | } 160 | } 161 | 162 | void endGroup() { 163 | if (GROUP_STARTED == groupState) { 164 | char mem[4]; 165 | BlynkParam cmd(mem, 0, sizeof(mem)); 166 | cmd.add("e"); 167 | static_cast(this)->sendCmd(BLYNK_CMD_GROUP, 0, cmd.getBuffer(), cmd.getLength()-1); 168 | } 169 | groupState = GROUP_NONE; 170 | } 171 | 172 | /** 173 | * Handler helpers 174 | */ 175 | void callWriteHandler(BlynkReq& req, const BlynkParam& param) { 176 | WidgetWriteHandler handler = GetWriteHandler(req.pin); 177 | if (handler && (handler != BlynkWidgetWrite)) { 178 | handler(req, param); 179 | } else { 180 | BlynkWidgetWriteDefault(req, param); 181 | } 182 | } 183 | 184 | void callReadHandler(BlynkReq& req) { 185 | WidgetReadHandler handler = GetReadHandler(req.pin); 186 | if (handler && (handler != BlynkWidgetRead)) { 187 | handler(req); 188 | } else { 189 | BlynkWidgetReadDefault(req); 190 | } 191 | } 192 | 193 | /** 194 | * Requests Server to re-send current values for all widgets. 195 | */ 196 | void syncAll() { 197 | static_cast(this)->sendCmd(BLYNK_CMD_HARDWARE_SYNC); 198 | } 199 | 200 | /** 201 | * Sends internal command 202 | */ 203 | template 204 | void sendInternal(Args... params) { 205 | char mem[BLYNK_MAX_SENDBYTES]; 206 | BlynkParam cmd(mem, 0, sizeof(mem)); 207 | cmd.add_multi(params...); 208 | static_cast(this)->sendCmd(BLYNK_CMD_INTERNAL, 0, cmd.getBuffer(), cmd.getLength()-1); 209 | } 210 | 211 | /** 212 | * Requests App or Server to re-send current value of a Virtual Pin. 213 | * This will probably cause user-defined BLYNK_WRITE handler to be called. 214 | * 215 | * @param pin Virtual Pin number 216 | */ 217 | template 218 | void syncVirtual(Args... pins) { 219 | char mem[BLYNK_MAX_SENDBYTES]; 220 | BlynkParam cmd(mem, 0, sizeof(mem)); 221 | cmd.add("vr"); 222 | cmd.add_multi(pins...); 223 | static_cast(this)->sendCmd(BLYNK_CMD_HARDWARE_SYNC, 0, cmd.getBuffer(), cmd.getLength()-1); 224 | } 225 | 226 | /** 227 | * Sets property of a Widget 228 | * 229 | * @experimental 230 | * 231 | * @param pin Virtual Pin number 232 | * @param property Property name ("label", "labels", "color", ...) 233 | * @param value Property value 234 | */ 235 | template 236 | void setProperty(int pin, const T& property, Args... values) { 237 | char mem[BLYNK_MAX_SENDBYTES]; 238 | BlynkParam cmd(mem, 0, sizeof(mem)); 239 | cmd.add(pin); 240 | cmd.add(property); 241 | cmd.add_multi(values...); 242 | static_cast(this)->sendCmd(BLYNK_CMD_PROPERTY, 0, cmd.getBuffer(), cmd.getLength()-1); 243 | } 244 | 245 | template 246 | void setProperty(int pin, const T& property, const BlynkParam& param) { 247 | char mem[32]; 248 | BlynkParam cmd(mem, 0, sizeof(mem)); 249 | cmd.add(pin); 250 | cmd.add(property); 251 | static_cast(this)->sendCmd(BLYNK_CMD_PROPERTY, 0, cmd.getBuffer(), cmd.getLength(), param.getBuffer(), param.getLength()-1); 252 | } 253 | 254 | template 255 | void setProperty(int pin, const T& property, const BlynkParamAllocated& param) { 256 | char mem[32]; 257 | BlynkParam cmd(mem, 0, sizeof(mem)); 258 | cmd.add(pin); 259 | cmd.add(property); 260 | static_cast(this)->sendCmd(BLYNK_CMD_PROPERTY, 0, cmd.getBuffer(), cmd.getLength(), param.getBuffer(), param.getLength()-1); 261 | } 262 | 263 | template 264 | void logEvent(const NAME& event_name) { 265 | char mem[BLYNK_MAX_SENDBYTES]; 266 | BlynkParam cmd(mem, 0, sizeof(mem)); 267 | cmd.add(event_name); 268 | static_cast(this)->sendCmd(BLYNK_CMD_EVENT_LOG, 0, cmd.getBuffer(), cmd.getLength()-1); 269 | } 270 | 271 | template 272 | void logEvent(const NAME& event_name, const DESCR& description) { 273 | char mem[BLYNK_MAX_SENDBYTES]; 274 | BlynkParam cmd(mem, 0, sizeof(mem)); 275 | cmd.add(event_name); 276 | cmd.add(description); 277 | static_cast(this)->sendCmd(BLYNK_CMD_EVENT_LOG, 0, cmd.getBuffer(), cmd.getLength()-1); 278 | } 279 | 280 | template 281 | void resolveEvent(const NAME& event_name) { 282 | char mem[BLYNK_MAX_SENDBYTES]; 283 | BlynkParam cmd(mem, 0, sizeof(mem)); 284 | cmd.add(event_name); 285 | static_cast(this)->sendCmd(BLYNK_CMD_EVENT_CLEAR, 0, cmd.getBuffer(), cmd.getLength()-1); 286 | } 287 | 288 | template 289 | void resolveAllEvents(const NAME& event_name) { 290 | char mem[BLYNK_MAX_SENDBYTES]; 291 | BlynkParam cmd(mem, 0, sizeof(mem)); 292 | cmd.add(event_name); 293 | cmd.add("all"); 294 | static_cast(this)->sendCmd(BLYNK_CMD_EVENT_CLEAR, 0, cmd.getBuffer(), cmd.getLength()-1); 295 | } 296 | 297 | #if defined(BLYNK_EXPERIMENTAL) 298 | // Attention! 299 | // Every function in this section may be changed, removed or renamed. 300 | 301 | /** 302 | * Refreshes value of a widget by running 303 | * user-defined BLYNK_READ handler of a pin. 304 | * 305 | * @experimental 306 | * 307 | * @param pin Virtual Pin number 308 | */ 309 | void refresh(int pin) { 310 | if (WidgetReadHandler handler = GetReadHandler(pin)) { 311 | BlynkReq req = { 0, BLYNK_SUCCESS, (uint8_t)pin }; 312 | handler(req); 313 | } 314 | } 315 | 316 | /** 317 | * Delays for N milliseconds, handling server communication in background. 318 | * 319 | * @experimental 320 | * @warning Should be used very carefully, especially on platforms with small RAM. 321 | * 322 | * @param ms Milliseconds to wait 323 | */ 324 | void delay(unsigned long ms) { 325 | uint16_t start = (uint16_t)micros(); 326 | while (ms > 0) { 327 | static_cast(this)->run(); 328 | #if !defined(BLYNK_NO_YIELD) 329 | yield(); 330 | #endif 331 | if (((uint16_t)micros() - start) >= 1000) { 332 | ms--; 333 | start += 1000; 334 | } 335 | } 336 | } 337 | 338 | #endif 339 | 340 | protected: 341 | void processCmd(const void* buff, size_t len); 342 | void sendInfo(); 343 | 344 | void sendPendingGroup() { 345 | if (GROUP_PENDING == groupState) { 346 | // Set groupState here as sendCmd is recursive 347 | groupState = GROUP_STARTED; 348 | if (groupTs) { 349 | char mem[24]; 350 | BlynkParam cmd(mem, 0, sizeof(mem)); 351 | cmd.add("t"); 352 | cmd.add(groupTs); 353 | static_cast(this)->sendCmd(BLYNK_CMD_GROUP, 0, cmd.getBuffer(), cmd.getLength()-1); 354 | } else { 355 | char mem[4]; 356 | BlynkParam cmd(mem, 0, sizeof(mem)); 357 | cmd.add("b"); 358 | static_cast(this)->sendCmd(BLYNK_CMD_GROUP, 0, cmd.getBuffer(), cmd.getLength()-1); 359 | } 360 | } 361 | } 362 | 363 | protected: 364 | enum GroupState { 365 | GROUP_NONE, 366 | GROUP_PENDING, 367 | GROUP_STARTED, 368 | } groupState; 369 | uint64_t groupTs; 370 | 371 | }; 372 | 373 | 374 | #endif 375 | -------------------------------------------------------------------------------- /src/Blynk/BlynkConfig.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkConfig.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Configuration of different aspects of library 8 | * 9 | */ 10 | 11 | #ifndef BlynkConfig_h 12 | #define BlynkConfig_h 13 | 14 | #include 15 | 16 | /*************************************************** 17 | * Change these settings to match your need 18 | ***************************************************/ 19 | #define BLYNK_DEFAULT_DOMAIN "blynk.cloud" 20 | #define BLYNK_DEFAULT_PORT 80 21 | #define BLYNK_DEFAULT_PORT_SSL 443 22 | 23 | /*************************************************** 24 | * Professional settings 25 | ***************************************************/ 26 | // Library version. 27 | #define BLYNK_VERSION "1.3.2" 28 | 29 | #define BLYNK_NEW_LIBRARY 30 | 31 | // Heartbeat period in seconds. 32 | #ifndef BLYNK_HEARTBEAT 33 | #define BLYNK_HEARTBEAT 45 34 | #endif 35 | 36 | // Network timeout in milliseconds. 37 | #ifndef BLYNK_TIMEOUT_MS 38 | #define BLYNK_TIMEOUT_MS 6000UL 39 | #endif 40 | 41 | // Limit the amount of outgoing commands per second. 42 | #ifndef BLYNK_MSG_LIMIT 43 | #define BLYNK_MSG_LIMIT 15 44 | #endif 45 | 46 | // Limit the incoming command length. 47 | #ifndef BLYNK_MAX_READBYTES 48 | #define BLYNK_MAX_READBYTES 256 49 | #endif 50 | 51 | // Limit the outgoing command length. 52 | #ifndef BLYNK_MAX_SENDBYTES 53 | #define BLYNK_MAX_SENDBYTES 128 54 | #endif 55 | 56 | // Uncomment to disable built-in analog and digital operations. 57 | //#define BLYNK_NO_BUILTIN 58 | 59 | // Uncomment to enable debug prints. 60 | //#define BLYNK_DEBUG 61 | 62 | // Uncomment to force-enable 128 virtual pins 63 | //#define BLYNK_USE_128_VPINS 64 | 65 | // Uncomment to disable fancy logo 66 | //#define BLYNK_NO_FANCY_LOGO 67 | 68 | // Uncomment to enable 3D fancy logo 69 | //#define BLYNK_FANCY_LOGO_3D 70 | 71 | // Uncomment to enable experimental functions. 72 | //#define BLYNK_EXPERIMENTAL 73 | 74 | // Uncomment to disable all float/double usage 75 | //#define BLYNK_NO_FLOAT 76 | 77 | // Uncomment to switch to direct-connect mode 78 | //#define BLYNK_USE_DIRECT_CONNECT 79 | 80 | 81 | // Uncomment to append command body to header (uses more RAM) 82 | //#define BLYNK_SEND_ATOMIC 83 | 84 | // Split whole command into chunks (in bytes) 85 | //#define BLYNK_SEND_CHUNK 64 86 | 87 | // Wait after sending each chunk (in milliseconds) 88 | //#define BLYNK_SEND_THROTTLE 10 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /src/Blynk/BlynkConsole.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkConsole.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2020 Volodymyr Shymanskyy 6 | * @date Oct 2020 7 | * @brief Console Utility 8 | * 9 | */ 10 | 11 | #ifndef BlynkConsole_h 12 | #define BlynkConsole_h 13 | 14 | #include 15 | #include 16 | 17 | #define BLYNK_CONSOLE_MAX_COMMANDS 64 18 | #define BLYNK_CONSOLE_INPUT_BUFFER 256 19 | #define BLYNK_CONSOLE_USE_STREAM 20 | 21 | #ifdef BLYNK_CONSOLE_USE_STREAM 22 | #include 23 | #endif 24 | 25 | #if defined(ARDUINO_AMEBA) 26 | #include // for strncasecmp 27 | #endif 28 | 29 | class BlynkConsole 30 | { 31 | private: 32 | 33 | #ifdef BLYNK_HAS_FUNCTIONAL_H 34 | typedef std::function HandlerSimp; 35 | typedef std::function HandlerArgs; 36 | typedef std::function HandlerParams; 37 | #else 38 | typedef void (*HandlerSimp)(); 39 | typedef void (*HandlerArgs)(int argc, const char** argv); 40 | typedef void (*HandlerParams)(const BlynkParam ¶m); 41 | #endif 42 | enum HandlerType { 43 | SIMPLE, 44 | WITH_ARGS, 45 | WITH_PARAMS, 46 | SUB_CONSOLE 47 | }; 48 | 49 | class CmdHandler { 50 | public: 51 | const char* cmd; 52 | HandlerType type; 53 | union { 54 | HandlerSimp* f_simp; 55 | HandlerArgs* f_args; 56 | HandlerParams* f_params; 57 | BlynkConsole* f_cons; 58 | }; 59 | CmdHandler() = default; 60 | CmdHandler(const char* s, HandlerSimp* f) 61 | : cmd(s), type(SIMPLE), f_simp(f) 62 | {} 63 | CmdHandler(const char* s, HandlerArgs* f) 64 | : cmd(s), type(WITH_ARGS), f_args(f) 65 | {} 66 | CmdHandler(const char* s, HandlerParams* f) 67 | : cmd(s), type(WITH_PARAMS), f_params(f) 68 | {} 69 | CmdHandler(const char* s, BlynkConsole* f) 70 | : cmd(s), type(SUB_CONSOLE), f_cons(f) 71 | {} 72 | }; 73 | 74 | public: 75 | 76 | enum ProcessResult { 77 | PROCESSED, 78 | SKIPPED, 79 | EXECUTED, 80 | NOT_FOUND, 81 | }; 82 | 83 | BlynkConsole() { 84 | reset_buff(); 85 | 86 | #if defined(BLYNK_CONSOLE_USE_STREAM) && defined(BLYNK_HAS_FUNCTIONAL_H) 87 | help = [=]() { 88 | if (!stream) return; 89 | stream->print("Available commands: "); 90 | for (size_t i=0; iprint(handler.cmd); 93 | if (i < commandsQty-1) { stream->print(", "); } 94 | } 95 | stream->println(); 96 | }; 97 | 98 | addCommand("help", help); 99 | addCommand("?", help); 100 | #endif 101 | 102 | } 103 | 104 | #ifdef BLYNK_CONSOLE_USE_STREAM 105 | void print() {} 106 | 107 | template 108 | void print(T val) { 109 | if (stream) stream->print(val); 110 | } 111 | 112 | template 113 | void print(T1 val1, T2 val2) { 114 | if (stream) stream->print(val1, val2); 115 | } 116 | 117 | void printf(const char *fmt, ... ) { 118 | if (stream) { 119 | char buf[256]; 120 | va_list args; 121 | va_start (args, fmt); 122 | vsnprintf(buf, sizeof(buf), (char*)fmt, args); 123 | va_end (args); 124 | stream->print(buf); 125 | } 126 | } 127 | #endif 128 | 129 | void addCommand(const char* cmd, HandlerSimp h) { 130 | if (commandsQty >= BLYNK_CONSOLE_MAX_COMMANDS) return; 131 | commands[commandsQty++] = CmdHandler(cmd, new HandlerSimp(h)); 132 | } 133 | 134 | void addCommand(const char* cmd, HandlerArgs h) { 135 | if (commandsQty >= BLYNK_CONSOLE_MAX_COMMANDS) return; 136 | commands[commandsQty++] = CmdHandler(cmd, new HandlerArgs(h)); 137 | } 138 | 139 | void addCommand(const char* cmd, HandlerParams h) { 140 | if (commandsQty >= BLYNK_CONSOLE_MAX_COMMANDS) return; 141 | commands[commandsQty++] = CmdHandler(cmd, new HandlerParams(h)); 142 | } 143 | 144 | void addCommand(const char* cmd, BlynkConsole* h) { 145 | if (commandsQty >= BLYNK_CONSOLE_MAX_COMMANDS || !h) return; 146 | #ifdef BLYNK_CONSOLE_USE_STREAM 147 | h->begin(stream); 148 | #endif 149 | commands[commandsQty++] = CmdHandler(cmd, h); 150 | } 151 | 152 | void addCommand(const char* cmd, BlynkConsole& h) { 153 | addCommand(cmd, &h); 154 | } 155 | 156 | ProcessResult process(char c) { 157 | if (cmdPtr >= cmdBuff+sizeof(cmdBuff)) { 158 | reset_buff(); 159 | } 160 | 161 | *(cmdPtr++) = c; 162 | if (c == '\n' || c == '\r') { 163 | return runCommandInBuff(); 164 | } 165 | return PROCESSED; 166 | } 167 | 168 | ProcessResult runCommand(const char* cmd) { 169 | strncpy(cmdBuff, cmd, sizeof(cmdBuff)); 170 | cmdBuff[sizeof(cmdBuff)-1] = '\0'; 171 | cmdPtr = cmdBuff + strlen(cmdBuff); 172 | return runCommandInBuff(); 173 | } 174 | 175 | private: 176 | 177 | ProcessResult runCommandInBuff() { 178 | char* argv[16]; 179 | int argc = split_argv(cmdBuff, argv, 16); 180 | if (argc <= 0) { 181 | return SKIPPED; 182 | } 183 | #ifdef BLYNK_CONSOLE_USE_STREAM 184 | if (stream) stream->println(); 185 | #endif 186 | ProcessResult ret = runCommand(argc, (const char**)argv); 187 | reset_buff(); 188 | return ret; 189 | } 190 | 191 | ProcessResult runCommand(int argc, const char** argv) { 192 | for (size_t i=0; i 0 && len < BLYNK_CONSOLE_INPUT_BUFFER) { 205 | char mem[len]; 206 | BlynkParam param(mem, 0, sizeof(mem)); 207 | for (int i = 1; i < argc; i++) { 208 | param.add(argv[i]); 209 | } 210 | (*(handler.f_params))(param); 211 | } 212 | break; 213 | } 214 | case SUB_CONSOLE: 215 | if (argc < 2) return NOT_FOUND; 216 | return handler.f_cons->runCommand(argc-1, (const char**)(argv+1)); 217 | } 218 | return EXECUTED; 219 | } 220 | } 221 | return NOT_FOUND; 222 | } 223 | 224 | public: 225 | 226 | #ifdef BLYNK_CONSOLE_USE_STREAM 227 | 228 | void begin(Stream& s) { 229 | stream = &s; 230 | } 231 | 232 | void begin(Stream* s) { 233 | stream = s; 234 | } 235 | 236 | Stream& getStream() { 237 | return *stream; 238 | } 239 | 240 | void run() { 241 | while (stream && stream->available()) { 242 | char c = stream->read(); 243 | switch (process(c)) { 244 | case SKIPPED: break; 245 | case PROCESSED: 246 | stream->print(c); 247 | break; 248 | case NOT_FOUND: 249 | stream->println("Command not found."); 250 | // Fall-through 251 | case EXECUTED: 252 | stream->print(">"); 253 | break; 254 | } 255 | } 256 | } 257 | #endif 258 | 259 | private: 260 | CmdHandler commands[BLYNK_CONSOLE_MAX_COMMANDS]; 261 | unsigned commandsQty = 0; 262 | 263 | char* cmdPtr; 264 | char cmdBuff[BLYNK_CONSOLE_INPUT_BUFFER]; 265 | 266 | #ifdef BLYNK_CONSOLE_USE_STREAM 267 | Stream* stream = nullptr; 268 | HandlerSimp help; 269 | #endif 270 | 271 | void reset_buff() { 272 | memset(cmdBuff, 0, sizeof(cmdBuff)); 273 | cmdPtr = cmdBuff; 274 | } 275 | 276 | static 277 | void unescape(char* buff) 278 | { 279 | char* outp = buff; 280 | while (*buff) { 281 | if (*buff == '\\') { 282 | switch (*(buff+1)) { 283 | case '0': *outp++ = '\0'; break; 284 | case 'b': *outp++ = '\b'; break; 285 | case 'n': *outp++ = '\n'; break; 286 | case 'r': *outp++ = '\r'; break; 287 | case 't': *outp++ = '\t'; break; 288 | case 'x': { 289 | char hex[3] = { *(buff+2), *(buff+3), '\0' }; 290 | *outp = strtol(hex, NULL, 16); 291 | buff += 2; outp += 1; 292 | break; 293 | } 294 | // Otherwise just pass the letter 295 | // Also handles '\\' 296 | default: *outp++ = *(buff+1); break; 297 | } 298 | buff += 2; 299 | } else { 300 | *outp++ = *buff++; 301 | } 302 | } 303 | *outp = '\0'; 304 | } 305 | 306 | static 307 | int split_argv(char *str, char** argv, int argv_capacity) 308 | { 309 | int result = 0; 310 | char* curr = str; 311 | int len = 0; 312 | memset(argv, 0, sizeof(char*)*argv_capacity); 313 | for (int i = 0; str[i] != '\0' && result < (argv_capacity-1); i++) { 314 | if (strchr(" \n\r\t", str[i])) { 315 | if (len) { // Found space after non-space 316 | str[i] = '\0'; 317 | unescape(curr); 318 | argv[result++] = curr; 319 | len = 0; 320 | } 321 | } else { 322 | if (!len) { // Found non-space after space 323 | curr = &str[i]; 324 | } 325 | len++; 326 | } 327 | } 328 | // Add final argument, if needed 329 | if (len && result < (argv_capacity-1)) { 330 | unescape(curr); 331 | argv[result++] = curr; 332 | } 333 | return result; 334 | } 335 | 336 | }; 337 | 338 | #endif // BlynkConsole 339 | -------------------------------------------------------------------------------- /src/Blynk/BlynkDateTime.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkDateTime.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2016 Volodymyr Shymanskyy 6 | * @date Aug 2016 7 | * @brief DateTime implementation 8 | * 9 | */ 10 | 11 | #ifndef BlynkDateTime_h 12 | #define BlynkDateTime_h 13 | 14 | #include 15 | 16 | typedef int64_t blynk_time_t; 17 | 18 | struct blynk_tm *blynk_gmtime_r(const blynk_time_t *time, struct blynk_tm *tm); 19 | blynk_time_t blynk_mk_gmtime(struct blynk_tm *tm); 20 | int blynk_compute_sun(int8_t month, int8_t day, double latitude, double longitude, bool rise); 21 | 22 | static inline 23 | bool isTimeValid(blynk_time_t t_sec) { 24 | return t_sec > 1609459200; // 01 Jan 2021 25 | } 26 | 27 | struct blynk_tm { 28 | int8_t tm_sec; // seconds after the minute 0-59 (max 61) 29 | int8_t tm_min; // minutes after the hour 0-59 30 | int8_t tm_hour; // minutes after the hour 0-23 31 | int8_t tm_mday; // day of the month 1-31 32 | int8_t tm_wday; // days since Sunday 0-6 33 | int8_t tm_mon; // months since January 0-11 34 | int16_t tm_year; // years since 1900 35 | int16_t tm_yday; // days since January 1 0-365 36 | }; 37 | 38 | #define BLYNK_SECS_PER_MIN (60UL) 39 | #define BLYNK_SECS_PER_HOUR (3600UL) 40 | #define BLYNK_SECS_PER_DAY (BLYNK_SECS_PER_HOUR * 24UL) 41 | #define BLYNK_SECS_PER_WEEK (BLYNK_SECS_PER_DAY * 7UL) 42 | 43 | static const char* DOW_STR[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 44 | 45 | class BlynkTime { 46 | 47 | public: 48 | static BlynkTime invalid() { return BlynkTime(); } 49 | 50 | static BlynkTime computeSunRise(int8_t month, int8_t day, double latitude, double longitude) { 51 | int minutes = blynk_compute_sun(month, day, latitude, longitude, true); 52 | if (minutes < 0) return invalid(); 53 | return BlynkTime(0, minutes, 0); 54 | } 55 | 56 | static BlynkTime computeSunSet(int8_t month, int8_t day, double latitude, double longitude) { 57 | int minutes = blynk_compute_sun(month, day, latitude, longitude, false); 58 | if (minutes < 0) return invalid(); 59 | return BlynkTime(0, minutes, 0); 60 | } 61 | 62 | 63 | BlynkTime() : mTime(-1) {} 64 | 65 | BlynkTime(const BlynkTime& t) : mTime(t.mTime) {} 66 | 67 | BlynkTime(long seconds) : mTime(seconds % BLYNK_SECS_PER_DAY) {} 68 | 69 | BlynkTime(int hour, int minute, int second) 70 | { 71 | mTime = (hour * BLYNK_SECS_PER_HOUR + minute * BLYNK_SECS_PER_MIN + second) % BLYNK_SECS_PER_DAY; 72 | } 73 | 74 | int second() const { return (mTime % BLYNK_SECS_PER_MIN); } 75 | int minute() const { return (mTime / BLYNK_SECS_PER_MIN) % BLYNK_SECS_PER_MIN; } 76 | int hour() const { return (mTime / BLYNK_SECS_PER_HOUR); } 77 | 78 | int hour12() const { 79 | int h = hour(); 80 | if (h == 0) 81 | return 12; // 12 midnight 82 | else if (h > 12) 83 | return h - 12; 84 | return h; 85 | } 86 | 87 | bool isAM() const { return !isPM(); } 88 | bool isPM() const { return (hour() >= 12); } 89 | 90 | void adjustSeconds(int sec) { 91 | if (isValid()) { 92 | mTime = (mTime + sec) % BLYNK_SECS_PER_DAY; 93 | } 94 | } 95 | 96 | blynk_time_t getUnixOffset() const { return mTime; } 97 | 98 | bool isValid() const { return mTime < BLYNK_SECS_PER_DAY; } 99 | operator bool() const { return isValid(); } 100 | 101 | bool operator != (const BlynkTime& t) const { return mTime != t.mTime; } 102 | bool operator == (const BlynkTime& t) const { return mTime == t.mTime; } 103 | bool operator >= (const BlynkTime& t) const { return mTime >= t.mTime; } 104 | bool operator <= (const BlynkTime& t) const { return mTime <= t.mTime; } 105 | bool operator > (const BlynkTime& t) const { return mTime > t.mTime; } 106 | bool operator < (const BlynkTime& t) const { return mTime < t.mTime; } 107 | 108 | BlynkTime& operator = (const BlynkTime& t) { mTime = t.mTime; return *this; } 109 | 110 | private: 111 | uint32_t mTime; 112 | }; 113 | 114 | class BlynkDateTime { 115 | 116 | public: 117 | static BlynkDateTime invalid() { return BlynkDateTime(); } 118 | 119 | BlynkDateTime() : mTime(0) {} 120 | 121 | BlynkDateTime(const BlynkDateTime& t) 122 | { 123 | mTime = t.mTime; 124 | blynk_gmtime_r(&mTime, &mTm); 125 | } 126 | 127 | BlynkDateTime(blynk_time_t t) 128 | { 129 | mTime = t; 130 | blynk_gmtime_r(&mTime, &mTm); 131 | } 132 | 133 | BlynkDateTime(int hour, int minute, int second, int day, int month, int year) 134 | { 135 | mTm.tm_hour = hour; 136 | mTm.tm_min = minute; 137 | mTm.tm_sec = second; 138 | 139 | mTm.tm_mday = day; 140 | mTm.tm_mon = month - 1; 141 | mTm.tm_year = year - 1900; 142 | 143 | mTime = blynk_mk_gmtime(&mTm); 144 | } 145 | 146 | BlynkDateTime(const BlynkTime& time, int day, int month, int year) 147 | : BlynkDateTime(time.hour(), time.minute(), time.second(), day, month, year) 148 | {} 149 | 150 | BlynkDateTime(const BlynkTime& time, const BlynkDateTime& date) 151 | : BlynkDateTime(time.hour(), time.minute(), time.second(), date.day(), date.month(), date.year()) 152 | {} 153 | 154 | int second() const { return mTm.tm_sec; } 155 | int minute() const { return mTm.tm_min; } 156 | int hour() const { return mTm.tm_hour; } 157 | int day() const { return mTm.tm_mday; } 158 | int month() const { return 1 + mTm.tm_mon; } 159 | int year() const { return 1900 + mTm.tm_year; } 160 | 161 | int yearday() const { return 1 + mTm.tm_yday; } // 1 = Jan 1, 2 = Jan 2 ... 162 | int weekday() const { return mTm.tm_wday; } // 0 = Sun, 1 = Mon ... 163 | 164 | // Deprecated: // 1 = Mon, ..., 7 = Sun 165 | int day_of_week() const { return mTm.tm_wday == 0 ? 7 : mTm.tm_wday; } 166 | int day_of_year() const { return 1 + mTm.tm_yday; } 167 | const char* dow_str() const { return DOW_STR[mTm.tm_wday % 7]; } 168 | 169 | int weak_of_year() const { 170 | int julian = yearday(); 171 | int dow = mTm.tm_wday; 172 | int dowJan1 = BlynkDateTime(0,0,0, 1,1,year()).weekday(); 173 | int weekNum = ((julian + 6) / 7); 174 | if (dow < dowJan1) { 175 | ++weekNum; 176 | } 177 | return (weekNum); 178 | } 179 | 180 | int getSecsToday() const { return mTime % BLYNK_SECS_PER_DAY; } 181 | int getSecsThisWeek() const { return (mTm.tm_wday * BLYNK_SECS_PER_DAY) + getSecsToday(); } 182 | BlynkDateTime getPrevMidnight() const { return BlynkDateTime((mTime / BLYNK_SECS_PER_DAY) * BLYNK_SECS_PER_DAY); } 183 | BlynkDateTime getNextMidnight() const { return BlynkDateTime((mTime / BLYNK_SECS_PER_DAY) * BLYNK_SECS_PER_DAY + BLYNK_SECS_PER_DAY); } 184 | BlynkDateTime getPrevSunday() const { return BlynkDateTime(mTime - getSecsThisWeek()); } 185 | BlynkDateTime getNextSunday() const { return BlynkDateTime(mTime - getSecsThisWeek() + BLYNK_SECS_PER_WEEK); } 186 | 187 | int hour12() const { 188 | int h = hour(); 189 | if (h == 0) 190 | return 12; // 12 midnight 191 | else if (h > 12) 192 | return h - 12; 193 | return h; 194 | } 195 | 196 | bool isAM() const { return !isPM(); } 197 | bool isPM() const { return (hour() >= 12); } 198 | 199 | void adjustSeconds(int sec) { 200 | if (isValid()) { 201 | mTime += sec; 202 | blynk_gmtime_r(&mTime, &mTm); 203 | } 204 | } 205 | 206 | //tm& getTm() { return mTm; } 207 | blynk_time_t getUnix() const { return mTime; } 208 | 209 | bool isValid() const { return mTime != 0; } 210 | operator blynk_time_t() const { return mTime; } 211 | 212 | bool operator != (const BlynkDateTime& t) const { return mTime != t.mTime; } 213 | bool operator == (const BlynkDateTime& t) const { return mTime == t.mTime; } 214 | bool operator >= (const BlynkDateTime& t) const { return mTime >= t.mTime; } 215 | bool operator <= (const BlynkDateTime& t) const { return mTime <= t.mTime; } 216 | bool operator > (const BlynkDateTime& t) const { return mTime > t.mTime; } 217 | bool operator < (const BlynkDateTime& t) const { return mTime < t.mTime; } 218 | 219 | private: 220 | blynk_tm mTm; 221 | blynk_time_t mTime; 222 | }; 223 | 224 | #endif 225 | -------------------------------------------------------------------------------- /src/Blynk/BlynkDebug.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkDebug.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Debug utilities 8 | * 9 | */ 10 | 11 | #ifndef BlynkDebug_h 12 | #define BlynkDebug_h 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #ifdef ESP8266 19 | extern "C" { 20 | #include "ets_sys.h" 21 | #include "os_type.h" 22 | #include "mem.h" 23 | } 24 | #else 25 | #include 26 | #endif 27 | 28 | #if defined(ARDUINO_ARCH_ARC32) 29 | typedef uint64_t millis_time_t; 30 | #else 31 | typedef uint32_t millis_time_t; 32 | #endif 33 | 34 | void BlynkDelay(millis_time_t ms); 35 | millis_time_t BlynkMillis(); 36 | size_t BlynkFreeRam(); 37 | void BlynkReset() BLYNK_NORETURN; 38 | void BlynkFatal() BLYNK_NORETURN; 39 | bool BlynkResetImplemented(); 40 | 41 | #if defined(BLYNK_DEBUG_ALL) && !(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)) 42 | #warning "Compiler features not enabled -> please contact yor board vendor to enable c++0x" 43 | #endif 44 | 45 | // Diagnostic defines 46 | 47 | #define BLYNK_FATAL(msg) { BLYNK_LOG1(msg); BlynkFatal(); } 48 | #define BLYNK_LOG_RAM() { BLYNK_LOG2(BLYNK_F("Free RAM: "), BlynkFreeRam()); } 49 | #define BLYNK_LOG_FN() BLYNK_LOG3(BLYNK_F(__FUNCTION__), '@', __LINE__); 50 | #define BLYNK_LOG_TROUBLE(t) BLYNK_LOG2(BLYNK_F("Trouble detected: http://docs.blynk.cc/#troubleshooting-"), t) 51 | 52 | #ifndef BLYNK_PRINT 53 | #undef BLYNK_DEBUG 54 | #endif 55 | 56 | #ifdef BLYNK_DEBUG_ALL 57 | #define BLYNK_DEBUG 58 | #endif 59 | 60 | #ifdef BLYNK_PRINT 61 | 62 | #if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE) 63 | 64 | #if defined(ARDUINO_ARCH_ARC32) 65 | // This will cause error - on purpose 66 | #define BLYNK_LOG(msg, ...) BLYNK_LOG_UNAVAILABLE(msg, ##__VA_ARGS__) 67 | #else 68 | #define BLYNK_LOG(msg, ...) blynk_dbg_print(BLYNK_PSTR(msg), ##__VA_ARGS__) 69 | #endif 70 | 71 | #define BLYNK_LOG1(p1) { BLYNK_LOG_TIME(); BLYNK_PRINT.println(p1); } 72 | #define BLYNK_LOG2(p1,p2) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.println(p2); } 73 | #define BLYNK_LOG3(p1,p2,p3) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.print(p2); BLYNK_PRINT.println(p3); } 74 | #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); } 75 | #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); } 76 | #define BLYNK_LOG_IP(msg, ip) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(BLYNK_F(msg)); \ 77 | BLYNK_PRINT.print(ip[0]); BLYNK_PRINT.print('.'); \ 78 | BLYNK_PRINT.print(ip[1]); BLYNK_PRINT.print('.'); \ 79 | BLYNK_PRINT.print(ip[2]); BLYNK_PRINT.print('.'); \ 80 | BLYNK_PRINT.println(ip[3]); } 81 | #define BLYNK_LOG_IP_REV(msg, ip) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(BLYNK_F(msg)); \ 82 | BLYNK_PRINT.print(ip[3]); BLYNK_PRINT.print('.'); \ 83 | BLYNK_PRINT.print(ip[2]); BLYNK_PRINT.print('.'); \ 84 | BLYNK_PRINT.print(ip[1]); BLYNK_PRINT.print('.'); \ 85 | BLYNK_PRINT.println(ip[0]); } 86 | 87 | static inline 88 | void BLYNK_LOG_TIME() { 89 | BLYNK_PRINT.print('['); 90 | BLYNK_PRINT.print(BlynkMillis()); 91 | BLYNK_PRINT.print(BLYNK_F("] ")); 92 | } 93 | 94 | #ifdef BLYNK_DEBUG 95 | #include 96 | #define BLYNK_DBG_BREAK() { for(;;); } 97 | #define BLYNK_ASSERT(expr) { if(!(expr)) { BLYNK_LOG2(BLYNK_F("Assertion failed: "), BLYNK_F(#expr)); BLYNK_DBG_BREAK() } } 98 | 99 | static inline 100 | void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) { 101 | if (len) { 102 | BLYNK_LOG_TIME(); 103 | BLYNK_PRINT.print(msg); 104 | int l2 = len; 105 | const uint8_t* octets = (const uint8_t*)addr; 106 | bool prev_print = true; 107 | while (l2--) { 108 | const uint8_t c = *octets++ & 0xFF; 109 | if (c > 32 && c < 127) { 110 | if (!prev_print) { BLYNK_PRINT.print(']'); } 111 | BLYNK_PRINT.print((char)c); 112 | prev_print = true; 113 | } else { 114 | BLYNK_PRINT.print(prev_print?'[':'|'); 115 | if (c < 0x10) { BLYNK_PRINT.print('0'); } 116 | BLYNK_PRINT.print(c, HEX); 117 | prev_print = false; 118 | } 119 | } 120 | if (!prev_print) { 121 | BLYNK_PRINT.print(']'); 122 | } 123 | BLYNK_PRINT.println(); 124 | } 125 | } 126 | #endif 127 | 128 | #if !defined(ARDUINO_ARCH_ARC32) 129 | #include 130 | #include 131 | 132 | static inline 133 | void blynk_dbg_print(const char* BLYNK_PROGMEM fmt, ...) 134 | { 135 | va_list ap; 136 | va_start(ap, fmt); 137 | char buff[128]; 138 | BLYNK_PRINT.print('['); 139 | BLYNK_PRINT.print(BlynkMillis()); 140 | BLYNK_PRINT.print(BLYNK_F("] ")); 141 | #if defined(__AVR__) 142 | vsnprintf_P(buff, sizeof(buff), fmt, ap); 143 | #else 144 | vsnprintf(buff, sizeof(buff), fmt, ap); 145 | #endif 146 | BLYNK_PRINT.println(buff); 147 | va_end(ap); 148 | } 149 | #endif // ARDUINO_ARCH_ARC32 150 | 151 | #elif defined(__MBED__) 152 | 153 | #define BLYNK_LOG(msg, ...) { BLYNK_PRINT.printf("[%ld] " msg BLYNK_NEWLINE, BlynkMillis(), ##__VA_ARGS__); } 154 | #define BLYNK_LOG1(p1) { BLYNK_LOG(p1);} 155 | #define BLYNK_LOG2(p1,p2) { BLYNK_LOG(p1,p2);} 156 | #define BLYNK_LOG3(p1,p2,p3) { BLYNK_LOG(p1,p2,p3);} 157 | #define BLYNK_LOG4(p1,p2,p3,p4) { BLYNK_LOG(p1,p2,p3,p4);} 158 | #define BLYNK_LOG6(p1,p2,p3,p4,p5,p6) { BLYNK_LOG(p1,p2,p3,p4,p5,p6);} 159 | 160 | #define BLYNK_LOG_TIME() BLYNK_PRINT.printf("[%ld]", BlynkMillis()); 161 | 162 | #ifdef BLYNK_DEBUG 163 | #define BLYNK_DBG_BREAK() raise(SIGTRAP); 164 | #define BLYNK_ASSERT(expr) assert(expr) 165 | 166 | static inline 167 | void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) { 168 | BLYNK_LOG_TIME(); 169 | BLYNK_PRINT.printf(msg); 170 | int l2 = len; 171 | const uint8_t* octets = (const uint8_t*)addr; 172 | bool prev_print = true; 173 | while (l2--) { 174 | const uint8_t c = *octets++ & 0xFF; 175 | if (c > 32 && c < 127) { 176 | if (!prev_print) { BLYNK_PRINT.putc(']'); } 177 | BLYNK_PRINT.putc((char)c); 178 | prev_print = true; 179 | } else { 180 | BLYNK_PRINT.putc(prev_print?'[':'|'); 181 | BLYNK_PRINT.printf("%02x", c); 182 | prev_print = false; 183 | } 184 | } 185 | BLYNK_PRINT.printf("%s" BLYNK_NEWLINE, prev_print?"":"]"); 186 | } 187 | #endif 188 | 189 | #elif defined(LINUX) 190 | 191 | #include 192 | #include 193 | #include 194 | #include 195 | #include 196 | 197 | #include 198 | using namespace std; 199 | #define BLYNK_LOG(msg, ...) { fprintf(BLYNK_PRINT, "[%ld] " msg BLYNK_NEWLINE, BlynkMillis(), ##__VA_ARGS__); } 200 | #define BLYNK_LOG1(p1) { BLYNK_LOG_TIME(); cout << p1 << endl; } 201 | #define BLYNK_LOG2(p1,p2) { BLYNK_LOG_TIME(); cout << p1 << p2 << endl; } 202 | #define BLYNK_LOG3(p1,p2,p3) { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << endl; } 203 | #define BLYNK_LOG4(p1,p2,p3,p4) { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << p4 << endl; } 204 | #define BLYNK_LOG6(p1,p2,p3,p4,p5,p6) { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << p4 << p5 << p6 << endl; } 205 | 206 | #define BLYNK_LOG_TIME() cout << '[' << BlynkMillis() << "] "; 207 | 208 | #ifdef BLYNK_DEBUG 209 | #define BLYNK_DBG_BREAK() raise(SIGTRAP); 210 | #define BLYNK_ASSERT(expr) assert(expr) 211 | 212 | static inline 213 | void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) { 214 | BLYNK_LOG_TIME(); 215 | fprintf(BLYNK_PRINT, "%s", msg); 216 | int l2 = len; 217 | const uint8_t* octets = (const uint8_t*)addr; 218 | bool prev_print = true; 219 | while (l2--) { 220 | const uint8_t c = *octets++ & 0xFF; 221 | if (c > 32 && c < 127) { 222 | if (!prev_print) { fputc(']', BLYNK_PRINT); } 223 | fputc((char)c, BLYNK_PRINT); 224 | prev_print = true; 225 | } else { 226 | fputc(prev_print?'[':'|', BLYNK_PRINT); 227 | fprintf(BLYNK_PRINT, "%02x", c); 228 | prev_print = false; 229 | } 230 | } 231 | fprintf(BLYNK_PRINT, "%s" BLYNK_NEWLINE, prev_print?"":"]"); 232 | } 233 | #endif 234 | 235 | #else 236 | 237 | #warning "Cannot detect platform" 238 | 239 | #endif 240 | 241 | #endif 242 | 243 | #ifndef BLYNK_LOG 244 | #define BLYNK_LOG(...) 245 | #define BLYNK_LOG1(p1) 246 | #define BLYNK_LOG2(p1,p2) 247 | #define BLYNK_LOG3(p1,p2,p3) 248 | #define BLYNK_LOG4(p1,p2,p3,p4) 249 | #define BLYNK_LOG6(p1,p2,p3,p4,p5,p6) 250 | #define BLYNK_LOG_IP(msg, ip) 251 | #define BLYNK_LOG_IP_REV(msg, ip) 252 | #endif 253 | 254 | #ifndef BLYNK_DBG_BREAK 255 | #define BLYNK_DBG_BREAK() 256 | #define BLYNK_ASSERT(expr) 257 | #define BLYNK_DBG_DUMP(msg, addr, len) 258 | #endif 259 | 260 | #endif 261 | -------------------------------------------------------------------------------- /src/Blynk/BlynkEveryN.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef BLYNKEVERYN_H 3 | #define BLYNKEVERYN_H 4 | 5 | #include 6 | 7 | millis_time_t blynk_count_millis() { 8 | const millis_time_t ms = BlynkMillis(); 9 | return ms; 10 | } 11 | 12 | uint16_t blynk_count_seconds16() { 13 | const millis_time_t ms = BlynkMillis(); 14 | return (ms / 1000); 15 | } 16 | 17 | uint16_t blynk_count_minutes16() 18 | { 19 | const millis_time_t ms = BlynkMillis(); 20 | return (ms / (60000L)) & 0xFFFF; 21 | } 22 | 23 | uint8_t blynk_count_hours8() 24 | { 25 | const millis_time_t ms = BlynkMillis(); 26 | return (ms / (3600000L)) & 0xFF; 27 | } 28 | 29 | template 30 | class BlynkPeriodic { 31 | public: 32 | T mPrev; 33 | T mPeriod; 34 | 35 | BlynkPeriodic() { reset(); mPeriod = 1; }; 36 | BlynkPeriodic(T period) { reset(); setPeriod(period); }; 37 | void setPeriod( T period) { mPeriod = period; }; 38 | T getTime() { return (T)(timeGetter()); }; 39 | T getPeriod() { return mPeriod; }; 40 | T getElapsed() { return getTime() - mPrev; } 41 | T getRemaining() { return mPeriod - getElapsed(); } 42 | T getLastTriggerTime() { return mPrev; } 43 | bool ready() { 44 | bool isReady = (getElapsed() >= mPeriod); 45 | if( isReady ) { reset(); } 46 | return isReady; 47 | } 48 | void reset() { mPrev = getTime(); }; 49 | void trigger() { mPrev = getTime() - mPeriod; }; 50 | 51 | operator bool() { return ready(); } 52 | }; 53 | 54 | typedef BlynkPeriodic BlynkEveryNMillis; 55 | typedef BlynkPeriodic BlynkEveryNSeconds; 56 | typedef BlynkPeriodic BlynkEveryNMinutes; 57 | typedef BlynkPeriodic BlynkEveryNHours; 58 | 59 | #define BLYNK_EVERY_N_MILLIS_I(NAME,N) static BlynkEveryNMillis NAME(N); if(NAME) 60 | #define BLYNK_EVERY_N_SECONDS_I(NAME,N) static BlynkEveryNSeconds NAME(N); if(NAME) 61 | #define BLYNK_EVERY_N_MINUTES_I(NAME,N) static BlynkEveryNMinutes NAME(N); if(NAME) 62 | #define BLYNK_EVERY_N_HOURS_I(NAME,N) static BlynkEveryNHours NAME(N); if(NAME) 63 | 64 | #define BLYNK_EVERY_N_MILLIS(N) BLYNK_EVERY_N_MILLIS_I(BLYNK_CONCAT2(PER, __COUNTER__),N) 65 | #define BLYNK_EVERY_N_SECONDS(N) BLYNK_EVERY_N_SECONDS_I(BLYNK_CONCAT2(PER, __COUNTER__),N) 66 | #define BLYNK_EVERY_N_MINUTES(N) BLYNK_EVERY_N_MINUTES_I(BLYNK_CONCAT2(PER, __COUNTER__),N) 67 | #define BLYNK_EVERY_N_HOURS(N) BLYNK_EVERY_N_HOURS_I(BLYNK_CONCAT2(PER, __COUNTER__),N) 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/Blynk/BlynkHandlers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkHandlers.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Handlers for virtual pin operations 8 | * 9 | */ 10 | 11 | #ifndef BlynkHandlers_h 12 | #define BlynkHandlers_h 13 | 14 | #include 15 | #include 16 | 17 | // Helper macro 18 | 19 | #define V0 0 20 | #define V1 1 21 | #define V2 2 22 | #define V3 3 23 | #define V4 4 24 | #define V5 5 25 | #define V6 6 26 | #define V7 7 27 | #define V8 8 28 | #define V9 9 29 | #define V10 10 30 | #define V11 11 31 | #define V12 12 32 | #define V13 13 33 | #define V14 14 34 | #define V15 15 35 | #define V16 16 36 | #define V17 17 37 | #define V18 18 38 | #define V19 19 39 | #define V20 20 40 | #define V21 21 41 | #define V22 22 42 | #define V23 23 43 | #define V24 24 44 | #define V25 25 45 | #define V26 26 46 | #define V27 27 47 | #define V28 28 48 | #define V29 29 49 | #define V30 30 50 | #define V31 31 51 | #ifdef BLYNK_USE_128_VPINS 52 | #define V32 32 53 | #define V33 33 54 | #define V34 34 55 | #define V35 35 56 | #define V36 36 57 | #define V37 37 58 | #define V38 38 59 | #define V39 39 60 | #define V40 40 61 | #define V41 41 62 | #define V42 42 63 | #define V43 43 64 | #define V44 44 65 | #define V45 45 66 | #define V46 46 67 | #define V47 47 68 | #define V48 48 69 | #define V49 49 70 | #define V50 50 71 | #define V51 51 72 | #define V52 52 73 | #define V53 53 74 | #define V54 54 75 | #define V55 55 76 | #define V56 56 77 | #define V57 57 78 | #define V58 58 79 | #define V59 59 80 | #define V60 60 81 | #define V61 61 82 | #define V62 62 83 | #define V63 63 84 | #define V64 64 85 | #define V65 65 86 | #define V66 66 87 | #define V67 67 88 | #define V68 68 89 | #define V69 69 90 | #define V70 70 91 | #define V71 71 92 | #define V72 72 93 | #define V73 73 94 | #define V74 74 95 | #define V75 75 96 | #define V76 76 97 | #define V77 77 98 | #define V78 78 99 | #define V79 79 100 | #define V80 80 101 | #define V81 81 102 | #define V82 82 103 | #define V83 83 104 | #define V84 84 105 | #define V85 85 106 | #define V86 86 107 | #define V87 87 108 | #define V88 88 109 | #define V89 89 110 | #define V90 90 111 | #define V91 91 112 | #define V92 92 113 | #define V93 93 114 | #define V94 94 115 | #define V95 95 116 | #define V96 96 117 | #define V97 97 118 | #define V98 98 119 | #define V99 99 120 | #define V100 100 121 | #define V101 101 122 | #define V102 102 123 | #define V103 103 124 | #define V104 104 125 | #define V105 105 126 | #define V106 106 127 | #define V107 107 128 | #define V108 108 129 | #define V109 109 130 | #define V110 110 131 | #define V111 111 132 | #define V112 112 133 | #define V113 113 134 | #define V114 114 135 | #define V115 115 136 | #define V116 116 137 | #define V117 117 138 | #define V118 118 139 | #define V119 119 140 | #define V120 120 141 | #define V121 121 142 | #define V122 122 143 | #define V123 123 144 | #define V124 124 145 | #define V125 125 146 | #define V126 126 147 | #define V127 127 148 | #endif 149 | 150 | // Initial syntax: 151 | #define BLYNK_WRITE_2(pin) \ 152 | void BlynkWidgetWrite ## pin (BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED ¶m) 153 | 154 | #define BLYNK_READ_2(pin) \ 155 | void BlynkWidgetRead ## pin (BlynkReq BLYNK_UNUSED &request) 156 | 157 | #define BLYNK_WRITE_DEFAULT() BLYNK_WRITE_2(Default) 158 | #define BLYNK_READ_DEFAULT() BLYNK_READ_2(Default) 159 | 160 | #define BLYNK_WRITE(pin) BLYNK_WRITE_2(pin) 161 | #define BLYNK_READ(pin) BLYNK_READ_2(pin) 162 | 163 | // New, more readable syntax: 164 | #define BLYNK_IN_2(pin) \ 165 | void BlynkWidgetWrite ## pin (BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED &getValue) 166 | 167 | #define BLYNK_OUT_2(pin) \ 168 | void BlynkWidgetRead ## pin (BlynkReq BLYNK_UNUSED &request) 169 | 170 | #define BLYNK_INPUT_DEFAULT() BLYNK_IN_2(Default) 171 | #define BLYNK_OUTPUT_DEFAULT() BLYNK_OUT_2(Default) 172 | 173 | #define BLYNK_INPUT(pin) BLYNK_IN_2(pin) 174 | #define BLYNK_OUTPUT(pin) BLYNK_OUT_2(pin) 175 | 176 | // Additional handlers 177 | #define BLYNK_CONNECTED() void BlynkOnConnected() 178 | #define BLYNK_DISCONNECTED() void BlynkOnDisconnected() 179 | 180 | // Advanced functions 181 | 182 | #define BLYNK_VAR_INT(name, pin) \ 183 | int name; \ 184 | BLYNK_WRITE(pin) { name = param.asInt(); } \ 185 | BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); } 186 | 187 | #define BLYNK_VAR_LONG(name, pin) \ 188 | long name; \ 189 | BLYNK_WRITE(pin) { name = param.asLong(); } \ 190 | BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); } 191 | 192 | #ifndef BLYNK_NO_FLOAT 193 | #define BLYNK_VAR_DOUBLE(name, pin) \ 194 | double name; \ 195 | BLYNK_WRITE(pin) { name = param.asDouble(); } \ 196 | BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); } 197 | #endif 198 | 199 | #ifdef ARDUINO 200 | #define BLYNK_VAR_STRING(name, pin) \ 201 | String name; \ 202 | BLYNK_WRITE(pin) { name = param.asStr(); } \ 203 | BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); } 204 | #endif 205 | 206 | // Default read/write handlers (you can redefine them in your code) 207 | #ifdef __cplusplus 208 | extern "C" { 209 | #endif 210 | 211 | struct BlynkReq 212 | { 213 | uint16_t pin; 214 | }; 215 | 216 | typedef void (*WidgetReadHandler)(BlynkReq BLYNK_UNUSED &request); 217 | typedef void (*WidgetWriteHandler)(BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED ¶m); 218 | 219 | WidgetReadHandler GetReadHandler(uint8_t pin); 220 | WidgetWriteHandler GetWriteHandler(uint8_t pin); 221 | 222 | // Declare placeholders 223 | BLYNK_READ(); 224 | BLYNK_WRITE(); 225 | void BlynkNoOpCbk(); 226 | 227 | // Declare all pin handlers (you can redefine them in your code) 228 | BLYNK_CONNECTED(); 229 | BLYNK_DISCONNECTED(); 230 | 231 | // Internal Virtual Pins 232 | BLYNK_WRITE(InternalPinACON); 233 | BLYNK_WRITE(InternalPinADIS); 234 | BLYNK_WRITE(InternalPinRTC); 235 | BLYNK_WRITE(InternalPinUTC); 236 | BLYNK_WRITE(InternalPinOTA); 237 | BLYNK_WRITE(InternalPinMETA); 238 | BLYNK_WRITE(InternalPinVFS); 239 | BLYNK_WRITE(InternalPinDBG); 240 | 241 | // Aliases 242 | //#define BLYNK_APP_CONNECTED() BLYNK_WRITE(InternalPinACON) 243 | //#define BLYNK_APP_DISCONNECTED() BLYNK_WRITE(InternalPinADIS) 244 | 245 | // Regular Virtual Pins 246 | BLYNK_READ_DEFAULT(); 247 | BLYNK_WRITE_DEFAULT(); 248 | 249 | BLYNK_READ(0 ); 250 | BLYNK_READ(1 ); 251 | BLYNK_READ(2 ); 252 | BLYNK_READ(3 ); 253 | BLYNK_READ(4 ); 254 | BLYNK_READ(5 ); 255 | BLYNK_READ(6 ); 256 | BLYNK_READ(7 ); 257 | BLYNK_READ(8 ); 258 | BLYNK_READ(9 ); 259 | BLYNK_READ(10); 260 | BLYNK_READ(11); 261 | BLYNK_READ(12); 262 | BLYNK_READ(13); 263 | BLYNK_READ(14); 264 | BLYNK_READ(15); 265 | BLYNK_READ(16); 266 | BLYNK_READ(17); 267 | BLYNK_READ(18); 268 | BLYNK_READ(19); 269 | BLYNK_READ(20); 270 | BLYNK_READ(21); 271 | BLYNK_READ(22); 272 | BLYNK_READ(23); 273 | BLYNK_READ(24); 274 | BLYNK_READ(25); 275 | BLYNK_READ(26); 276 | BLYNK_READ(27); 277 | BLYNK_READ(28); 278 | BLYNK_READ(29); 279 | BLYNK_READ(30); 280 | BLYNK_READ(31); 281 | #ifdef BLYNK_USE_128_VPINS 282 | BLYNK_READ(32); 283 | BLYNK_READ(33); 284 | BLYNK_READ(34); 285 | BLYNK_READ(35); 286 | BLYNK_READ(36); 287 | BLYNK_READ(37); 288 | BLYNK_READ(38); 289 | BLYNK_READ(39); 290 | BLYNK_READ(40); 291 | BLYNK_READ(41); 292 | BLYNK_READ(42); 293 | BLYNK_READ(43); 294 | BLYNK_READ(44); 295 | BLYNK_READ(45); 296 | BLYNK_READ(46); 297 | BLYNK_READ(47); 298 | BLYNK_READ(48); 299 | BLYNK_READ(49); 300 | BLYNK_READ(50); 301 | BLYNK_READ(51); 302 | BLYNK_READ(52); 303 | BLYNK_READ(53); 304 | BLYNK_READ(54); 305 | BLYNK_READ(55); 306 | BLYNK_READ(56); 307 | BLYNK_READ(57); 308 | BLYNK_READ(58); 309 | BLYNK_READ(59); 310 | BLYNK_READ(60); 311 | BLYNK_READ(61); 312 | BLYNK_READ(62); 313 | BLYNK_READ(63); 314 | BLYNK_READ(64); 315 | BLYNK_READ(65); 316 | BLYNK_READ(66); 317 | BLYNK_READ(67); 318 | BLYNK_READ(68); 319 | BLYNK_READ(69); 320 | BLYNK_READ(70); 321 | BLYNK_READ(71); 322 | BLYNK_READ(72); 323 | BLYNK_READ(73); 324 | BLYNK_READ(74); 325 | BLYNK_READ(75); 326 | BLYNK_READ(76); 327 | BLYNK_READ(77); 328 | BLYNK_READ(78); 329 | BLYNK_READ(79); 330 | BLYNK_READ(80); 331 | BLYNK_READ(81); 332 | BLYNK_READ(82); 333 | BLYNK_READ(83); 334 | BLYNK_READ(84); 335 | BLYNK_READ(85); 336 | BLYNK_READ(86); 337 | BLYNK_READ(87); 338 | BLYNK_READ(88); 339 | BLYNK_READ(89); 340 | BLYNK_READ(90); 341 | BLYNK_READ(91); 342 | BLYNK_READ(92); 343 | BLYNK_READ(93); 344 | BLYNK_READ(94); 345 | BLYNK_READ(95); 346 | BLYNK_READ(96); 347 | BLYNK_READ(97); 348 | BLYNK_READ(98); 349 | BLYNK_READ(99); 350 | BLYNK_READ(100); 351 | BLYNK_READ(101); 352 | BLYNK_READ(102); 353 | BLYNK_READ(103); 354 | BLYNK_READ(104); 355 | BLYNK_READ(105); 356 | BLYNK_READ(106); 357 | BLYNK_READ(107); 358 | BLYNK_READ(108); 359 | BLYNK_READ(109); 360 | BLYNK_READ(110); 361 | BLYNK_READ(111); 362 | BLYNK_READ(112); 363 | BLYNK_READ(113); 364 | BLYNK_READ(114); 365 | BLYNK_READ(115); 366 | BLYNK_READ(116); 367 | BLYNK_READ(117); 368 | BLYNK_READ(118); 369 | BLYNK_READ(119); 370 | BLYNK_READ(120); 371 | BLYNK_READ(121); 372 | BLYNK_READ(122); 373 | BLYNK_READ(123); 374 | BLYNK_READ(124); 375 | BLYNK_READ(125); 376 | BLYNK_READ(126); 377 | BLYNK_READ(127); 378 | #endif 379 | 380 | BLYNK_WRITE(0 ); 381 | BLYNK_WRITE(1 ); 382 | BLYNK_WRITE(2 ); 383 | BLYNK_WRITE(3 ); 384 | BLYNK_WRITE(4 ); 385 | BLYNK_WRITE(5 ); 386 | BLYNK_WRITE(6 ); 387 | BLYNK_WRITE(7 ); 388 | BLYNK_WRITE(8 ); 389 | BLYNK_WRITE(9 ); 390 | BLYNK_WRITE(10); 391 | BLYNK_WRITE(11); 392 | BLYNK_WRITE(12); 393 | BLYNK_WRITE(13); 394 | BLYNK_WRITE(14); 395 | BLYNK_WRITE(15); 396 | BLYNK_WRITE(16); 397 | BLYNK_WRITE(17); 398 | BLYNK_WRITE(18); 399 | BLYNK_WRITE(19); 400 | BLYNK_WRITE(20); 401 | BLYNK_WRITE(21); 402 | BLYNK_WRITE(22); 403 | BLYNK_WRITE(23); 404 | BLYNK_WRITE(24); 405 | BLYNK_WRITE(25); 406 | BLYNK_WRITE(26); 407 | BLYNK_WRITE(27); 408 | BLYNK_WRITE(28); 409 | BLYNK_WRITE(29); 410 | BLYNK_WRITE(30); 411 | BLYNK_WRITE(31); 412 | #ifdef BLYNK_USE_128_VPINS 413 | BLYNK_WRITE(32); 414 | BLYNK_WRITE(33); 415 | BLYNK_WRITE(34); 416 | BLYNK_WRITE(35); 417 | BLYNK_WRITE(36); 418 | BLYNK_WRITE(37); 419 | BLYNK_WRITE(38); 420 | BLYNK_WRITE(39); 421 | BLYNK_WRITE(40); 422 | BLYNK_WRITE(41); 423 | BLYNK_WRITE(42); 424 | BLYNK_WRITE(43); 425 | BLYNK_WRITE(44); 426 | BLYNK_WRITE(45); 427 | BLYNK_WRITE(46); 428 | BLYNK_WRITE(47); 429 | BLYNK_WRITE(48); 430 | BLYNK_WRITE(49); 431 | BLYNK_WRITE(50); 432 | BLYNK_WRITE(51); 433 | BLYNK_WRITE(52); 434 | BLYNK_WRITE(53); 435 | BLYNK_WRITE(54); 436 | BLYNK_WRITE(55); 437 | BLYNK_WRITE(56); 438 | BLYNK_WRITE(57); 439 | BLYNK_WRITE(58); 440 | BLYNK_WRITE(59); 441 | BLYNK_WRITE(60); 442 | BLYNK_WRITE(61); 443 | BLYNK_WRITE(62); 444 | BLYNK_WRITE(63); 445 | BLYNK_WRITE(64); 446 | BLYNK_WRITE(65); 447 | BLYNK_WRITE(66); 448 | BLYNK_WRITE(67); 449 | BLYNK_WRITE(68); 450 | BLYNK_WRITE(69); 451 | BLYNK_WRITE(70); 452 | BLYNK_WRITE(71); 453 | BLYNK_WRITE(72); 454 | BLYNK_WRITE(73); 455 | BLYNK_WRITE(74); 456 | BLYNK_WRITE(75); 457 | BLYNK_WRITE(76); 458 | BLYNK_WRITE(77); 459 | BLYNK_WRITE(78); 460 | BLYNK_WRITE(79); 461 | BLYNK_WRITE(80); 462 | BLYNK_WRITE(81); 463 | BLYNK_WRITE(82); 464 | BLYNK_WRITE(83); 465 | BLYNK_WRITE(84); 466 | BLYNK_WRITE(85); 467 | BLYNK_WRITE(86); 468 | BLYNK_WRITE(87); 469 | BLYNK_WRITE(88); 470 | BLYNK_WRITE(89); 471 | BLYNK_WRITE(90); 472 | BLYNK_WRITE(91); 473 | BLYNK_WRITE(92); 474 | BLYNK_WRITE(93); 475 | BLYNK_WRITE(94); 476 | BLYNK_WRITE(95); 477 | BLYNK_WRITE(96); 478 | BLYNK_WRITE(97); 479 | BLYNK_WRITE(98); 480 | BLYNK_WRITE(99); 481 | BLYNK_WRITE(100); 482 | BLYNK_WRITE(101); 483 | BLYNK_WRITE(102); 484 | BLYNK_WRITE(103); 485 | BLYNK_WRITE(104); 486 | BLYNK_WRITE(105); 487 | BLYNK_WRITE(106); 488 | BLYNK_WRITE(107); 489 | BLYNK_WRITE(108); 490 | BLYNK_WRITE(109); 491 | BLYNK_WRITE(110); 492 | BLYNK_WRITE(111); 493 | BLYNK_WRITE(112); 494 | BLYNK_WRITE(113); 495 | BLYNK_WRITE(114); 496 | BLYNK_WRITE(115); 497 | BLYNK_WRITE(116); 498 | BLYNK_WRITE(117); 499 | BLYNK_WRITE(118); 500 | BLYNK_WRITE(119); 501 | BLYNK_WRITE(120); 502 | BLYNK_WRITE(121); 503 | BLYNK_WRITE(122); 504 | BLYNK_WRITE(123); 505 | BLYNK_WRITE(124); 506 | BLYNK_WRITE(125); 507 | BLYNK_WRITE(126); 508 | BLYNK_WRITE(127); 509 | #endif 510 | 511 | #ifdef __cplusplus 512 | } 513 | #endif 514 | 515 | #endif 516 | -------------------------------------------------------------------------------- /src/Blynk/BlynkHelpers.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkHelpers.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2016 Volodymyr Shymanskyy 6 | * @date May 2016 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkHelpers_h 12 | #define BlynkHelpers_h 13 | 14 | #if defined(SPARK) || defined(PARTICLE) 15 | #include "application.h" 16 | #endif 17 | 18 | #if defined(ARDUINO) 19 | #if ARDUINO >= 100 20 | #include 21 | #else 22 | #include 23 | #endif 24 | #endif 25 | 26 | #if defined(LINUX) 27 | #if defined(RASPBERRY) 28 | #include 29 | #endif 30 | #endif 31 | 32 | #include 33 | #include 34 | 35 | // General defines 36 | 37 | #define BLYNK_NEWLINE "\r\n" 38 | 39 | #define BLYNK_CONCAT(a, b) a ## b 40 | #define BLYNK_CONCAT2(a, b) BLYNK_CONCAT(a, b) 41 | 42 | #define BLYNK_STRINGIFY(x) #x 43 | #define BLYNK_TOSTRING(x) BLYNK_STRINGIFY(x) 44 | 45 | #define BLYNK_COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 46 | 47 | #define BLYNK_ATTR_PACKED __attribute__ ((__packed__)) 48 | #define BLYNK_NORETURN __attribute__ ((noreturn)) 49 | #define BLYNK_UNUSED __attribute__ ((__unused__)) 50 | #define BLYNK_DEPRECATED __attribute__ ((deprecated)) 51 | #define BLYNK_CONSTRUCTOR __attribute__ ((constructor)) 52 | #define BLYNK_FALLTHROUGH __attribute__ ((fallthrough)) 53 | 54 | // Causes problems on some platforms 55 | #define BLYNK_FORCE_INLINE inline //__attribute__((always_inline)) 56 | 57 | #if !defined(BLYNK_RUN_YIELD) 58 | #if defined(BLYNK_NO_YIELD) 59 | #define BLYNK_RUN_YIELD() {} 60 | #elif defined(SPARK) || defined(PARTICLE) 61 | #define BLYNK_RUN_YIELD() { Particle.process(); } 62 | #elif !defined(ARDUINO) || (ARDUINO < 151) 63 | #define BLYNK_RUN_YIELD() {} 64 | #else 65 | #define BLYNK_RUN_YIELD() { BlynkDelay(0); } 66 | #endif 67 | #endif 68 | 69 | #if defined(__AVR__) 70 | #include 71 | #define BLYNK_HAS_PROGMEM 72 | #define BLYNK_PROGMEM PROGMEM 73 | #define BLYNK_F(s) F(s) 74 | #define BLYNK_PSTR(s) PSTR(s) 75 | #else 76 | #define BLYNK_PROGMEM 77 | #define BLYNK_F(s) s 78 | #define BLYNK_PSTR(s) s 79 | #endif 80 | 81 | #if defined(__has_include) 82 | #if __has_include() 83 | #include 84 | #define BLYNK_HAS_FUNCTIONAL_H 85 | #endif 86 | #endif 87 | 88 | #if defined(BLYNK_MULTITHREADED) 89 | #include 90 | 91 | #define BLYNK_MUTEX_DECL(x) std::mutex x 92 | #define BLYNK_MUTEX_GUARD(x) std::lock_guard BLYNK_CONCAT2(lg_, __LINE__)(x) 93 | #else 94 | #define BLYNK_MUTEX_DECL(x) 95 | #define BLYNK_MUTEX_GUARD(x) 96 | #endif 97 | 98 | #ifdef ARDUINO_AVR_DIGISPARK 99 | typedef fstr_t __FlashStringHelper; 100 | #endif 101 | 102 | #endif /* BlynkHelpers_h */ 103 | -------------------------------------------------------------------------------- /src/Blynk/BlynkParam.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkParam.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Container for handler parameters 8 | * 9 | */ 10 | 11 | #ifndef BlynkParam_h 12 | #define BlynkParam_h 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define BLYNK_PARAM_KV(k, v) k "\0" v "\0" 20 | #define BLYNK_PARAM_PLACEHOLDER_64 "PlaceholderPlaceholderPlaceholderPlaceholderPlaceholderPlaceholder" 21 | 22 | #if !defined(BLYNK_NO_FLOAT) 23 | extern char* dtostrf_internal(double number, signed char width, unsigned char prec, char *s); 24 | #endif 25 | 26 | #if !defined(BLYNK_NO_LONGLONG) 27 | extern long long atoll_internal(const char *s); 28 | extern char* lltoa_internal(long long val, char* buf, unsigned buf_len, int base); 29 | extern char* ulltoa_internal(unsigned long long val, char* buf, unsigned buf_len, int base); 30 | #endif 31 | 32 | class BlynkParam 33 | { 34 | public: 35 | class iterator 36 | { 37 | public: 38 | iterator(const char* c, const char* l) : ptr(c), limit(l) {} 39 | static iterator invalid() { return iterator(NULL, NULL); } 40 | 41 | operator const char* () const { return asStr(); } 42 | operator int () const { return asInt(); } 43 | const char* asStr() const { return ptr; } 44 | const char* asString() const { return ptr; } 45 | int asInt() const { if(!isValid()) return 0; return atoi(ptr); } 46 | long asLong() const { if(!isValid()) return 0; return atol(ptr); } 47 | #if !defined(BLYNK_NO_LONGLONG) && defined(BLYNK_USE_INTERNAL_ATOLL) 48 | long long asLongLong() const { return atoll_internal(ptr); } 49 | #elif !defined(BLYNK_NO_LONGLONG) 50 | long long asLongLong() const { return atoll(ptr); } 51 | #endif 52 | #if !defined(BLYNK_NO_FLOAT) 53 | double asDouble() const { if(!isValid()) return 0; return atof(ptr); } 54 | float asFloat() const { if(!isValid()) return 0; return atof(ptr); } 55 | #endif 56 | bool isValid() const { return ptr != NULL && ptr < limit; } 57 | bool isEmpty() const { if(!isValid()) return true; return *ptr == '\0'; } 58 | 59 | bool operator < (const iterator& it) const { return ptr < it.ptr; } 60 | bool operator >= (const iterator& it) const { return ptr >= it.ptr; } 61 | 62 | iterator& operator ++() { 63 | if(isValid()) { 64 | ptr += strlen(ptr) + 1; 65 | } 66 | return *this; 67 | } 68 | private: 69 | const char* ptr; 70 | const char* limit; 71 | }; 72 | 73 | public: 74 | explicit 75 | BlynkParam(const void* addr, size_t length) 76 | : buff((char*)addr), len(length), buff_size(length) 77 | {} 78 | 79 | explicit 80 | BlynkParam(void* addr, size_t length, size_t buffsize) 81 | : buff((char*)addr), len(length), buff_size(buffsize) 82 | {} 83 | 84 | const char* asStr() const { return buff; } 85 | const char* asString() const { return buff; } 86 | int asInt() const { return atoi(buff); } 87 | long asLong() const { return atol(buff); } 88 | #if !defined(BLYNK_NO_LONGLONG) && defined(BLYNK_USE_INTERNAL_ATOLL) 89 | long long asLongLong() const { return atoll_internal(buff); } 90 | #elif !defined(BLYNK_NO_LONGLONG) 91 | long long asLongLong() const { return atoll(buff); } 92 | #endif 93 | #if !defined(BLYNK_NO_FLOAT) 94 | double asDouble() const { return atof(buff); } 95 | float asFloat() const { return atof(buff); } 96 | #endif 97 | bool isEmpty() const { return *buff == '\0'; } 98 | 99 | iterator begin() const { return iterator(buff, buff+len); } 100 | iterator end() const { return iterator(buff+len, buff+len); } 101 | 102 | iterator operator[](int index) const; 103 | iterator operator[](const char* key) const; 104 | 105 | void* getBuffer() const { return (void*)buff; } 106 | size_t getLength() const { return len; } 107 | size_t getBuffSize() const { return buff_size; } 108 | 109 | // Modification 110 | void clear() { len = 0; } 111 | 112 | void add(int value); 113 | void add(unsigned int value); 114 | void add(long value); 115 | void add(unsigned long value); 116 | void add(long long value); 117 | void add(unsigned long long value); 118 | #ifndef BLYNK_NO_FLOAT 119 | void add(float value); 120 | void add(double value); 121 | #endif 122 | void add(const char* str); 123 | #if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE) 124 | void add(const String& str); 125 | #if defined(BLYNK_HAS_PROGMEM) 126 | void add(const __FlashStringHelper* str); 127 | #endif 128 | #endif 129 | 130 | template 131 | void add_multi(T last) { 132 | add(last); 133 | } 134 | 135 | template 136 | void add_multi(T head, Args... tail) { 137 | add(head); 138 | add_multi(tail...); 139 | } 140 | 141 | template 142 | void add_key(const char* key, const TV& val) { 143 | add(key); 144 | add(val); 145 | } 146 | 147 | void remove_key(const char* key); 148 | 149 | void add_raw(const void* b, size_t l); 150 | 151 | protected: 152 | char* buff; 153 | size_t len; 154 | size_t buff_size; 155 | }; 156 | 157 | 158 | class BlynkParamAllocated 159 | : public BlynkParam 160 | { 161 | public: 162 | BlynkParamAllocated(size_t size) 163 | : BlynkParam(malloc(size), 0, size) 164 | {} 165 | ~BlynkParamAllocated() { 166 | free(buff); 167 | } 168 | }; 169 | 170 | inline 171 | BlynkParam::iterator BlynkParam::operator[](int index) const 172 | { 173 | const iterator e = end(); 174 | for (iterator it = begin(); it < e; ++it) { 175 | if (!index--) { 176 | return it; 177 | } 178 | } 179 | return iterator::invalid(); 180 | } 181 | 182 | inline 183 | BlynkParam::iterator BlynkParam::operator[](const char* key) const 184 | { 185 | const iterator e = end(); 186 | for (iterator it = begin(); it < e; ++it) { 187 | if (!strcmp(it.asStr(), key)) { 188 | return ++it; 189 | } 190 | ++it; 191 | if (it >= e) break; 192 | } 193 | return iterator::invalid(); 194 | } 195 | 196 | inline 197 | void BlynkParam::remove_key(const char* key) 198 | { 199 | bool found; 200 | do { 201 | found = false; 202 | const iterator e = end(); 203 | for (iterator it = begin(); it < e; ++it) { 204 | if (!strcmp(it.asStr(), key)) { 205 | const char* key = it.asStr(); 206 | ++it; ++it; 207 | const char* next = it.asStr(); 208 | memmove((void*)key, next, (buff+len)-next); 209 | len -= (next-key); 210 | found = true; 211 | break; 212 | } 213 | ++it; 214 | if (it >= e) break; 215 | } 216 | } while (found); 217 | } 218 | 219 | inline 220 | void BlynkParam::add_raw(const void* b, size_t l) 221 | { 222 | if (len + l > buff_size) 223 | return; 224 | memcpy(buff+len, b, l); 225 | len += l; 226 | } 227 | 228 | inline 229 | void BlynkParam::add(const char* str) 230 | { 231 | if (str == NULL) { 232 | buff[len++] = '\0'; 233 | return; 234 | } 235 | add_raw(str, strlen(str)+1); 236 | } 237 | 238 | #if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE) 239 | inline 240 | void BlynkParam::add(const String& str) 241 | { 242 | #if defined(ARDUINO_AVR_DIGISPARK) \ 243 | || defined(__ARDUINO_X86__) \ 244 | || defined(__RFduino__) 245 | 246 | size_t len = str.length()+1; 247 | char buff[len]; 248 | const_cast(str).toCharArray(buff, len); 249 | add_raw(buff, len); 250 | #else 251 | add(str.c_str()); 252 | #endif 253 | } 254 | 255 | #if defined(BLYNK_HAS_PROGMEM) 256 | 257 | inline 258 | void BlynkParam::add(const __FlashStringHelper* ifsh) 259 | { 260 | PGM_P p = reinterpret_cast(ifsh); 261 | size_t l = strlen_P(p) + 1; 262 | if (len + l > buff_size) 263 | return; 264 | memcpy_P(buff+len, p, l); 265 | len += l; 266 | buff[len] = '\0'; 267 | } 268 | 269 | #endif 270 | 271 | #endif 272 | 273 | #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32) 274 | 275 | #include 276 | 277 | inline 278 | void BlynkParam::add(int value) 279 | { 280 | char str[2 + 3 * sizeof(value)]; 281 | itoa(value, str, 10); 282 | add(str); 283 | } 284 | 285 | inline 286 | void BlynkParam::add(unsigned int value) 287 | { 288 | char str[1 + 3 * sizeof(value)]; 289 | utoa(value, str, 10); 290 | add(str); 291 | } 292 | 293 | inline 294 | void BlynkParam::add(long value) 295 | { 296 | char str[2 + 3 * sizeof(value)]; 297 | ltoa(value, str, 10); 298 | add(str); 299 | } 300 | 301 | inline 302 | void BlynkParam::add(unsigned long value) 303 | { 304 | char str[1 + 3 * sizeof(value)]; 305 | ultoa(value, str, 10); 306 | add(str); 307 | } 308 | 309 | #if !defined(BLYNK_NO_LONGLONG) 310 | 311 | inline 312 | void BlynkParam::add(long long value) 313 | { 314 | char str[2 + 3 * sizeof(value)]; 315 | add(lltoa_internal(value, str, sizeof(str), 10)); 316 | } 317 | 318 | inline 319 | void BlynkParam::add(unsigned long long value) 320 | { 321 | char str[1 + 3 * sizeof(value)]; 322 | add(ulltoa_internal(value, str, sizeof(str), 10)); 323 | } 324 | 325 | #endif 326 | 327 | #ifndef BLYNK_NO_FLOAT 328 | 329 | inline 330 | void BlynkParam::add(float value) 331 | { 332 | char str[33]; 333 | dtostrf(value, 5, 3, str); 334 | add(str); 335 | } 336 | 337 | inline 338 | void BlynkParam::add(double value) 339 | { 340 | char str[33]; 341 | dtostrf(value, 5, 7, str); 342 | add(str); 343 | } 344 | #endif 345 | 346 | #else 347 | 348 | #include 349 | 350 | inline 351 | void BlynkParam::add(int value) 352 | { 353 | len += snprintf(buff+len, buff_size-len, "%i", value)+1; 354 | } 355 | 356 | inline 357 | void BlynkParam::add(unsigned int value) 358 | { 359 | len += snprintf(buff+len, buff_size-len, "%u", value)+1; 360 | } 361 | 362 | inline 363 | void BlynkParam::add(long value) 364 | { 365 | len += snprintf(buff+len, buff_size-len, "%li", value)+1; 366 | } 367 | 368 | inline 369 | void BlynkParam::add(unsigned long value) 370 | { 371 | len += snprintf(buff+len, buff_size-len, "%lu", value)+1; 372 | } 373 | 374 | inline 375 | void BlynkParam::add(long long value) 376 | { 377 | len += snprintf(buff+len, buff_size-len, "%lli", value)+1; 378 | } 379 | 380 | inline 381 | void BlynkParam::add(unsigned long long value) 382 | { 383 | len += snprintf(buff+len, buff_size-len, "%llu", value)+1; 384 | } 385 | 386 | #ifndef BLYNK_NO_FLOAT 387 | 388 | #if defined(BLYNK_USE_INTERNAL_DTOSTRF) 389 | 390 | inline 391 | void BlynkParam::add(float value) 392 | { 393 | char str[33]; 394 | dtostrf_internal(value, 5, 3, str); 395 | add(str); 396 | } 397 | 398 | inline 399 | void BlynkParam::add(double value) 400 | { 401 | char str[33]; 402 | dtostrf_internal(value, 5, 7, str); 403 | add(str); 404 | } 405 | 406 | #else 407 | 408 | inline 409 | void BlynkParam::add(float value) 410 | { 411 | len += snprintf(buff+len, buff_size-len, "%2.3f", value)+1; 412 | } 413 | 414 | inline 415 | void BlynkParam::add(double value) 416 | { 417 | len += snprintf(buff+len, buff_size-len, "%2.7f", value)+1; 418 | } 419 | 420 | #endif 421 | 422 | #endif 423 | 424 | #endif 425 | 426 | 427 | #endif 428 | -------------------------------------------------------------------------------- /src/Blynk/BlynkProtocol.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkProtocol.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Blynk protocol implementation 8 | * 9 | */ 10 | 11 | #ifndef BlynkProtocol_h 12 | #define BlynkProtocol_h 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | template 21 | class BlynkProtocol 22 | : public BlynkApi< BlynkProtocol > 23 | { 24 | friend class BlynkApi< BlynkProtocol >; 25 | public: 26 | enum BlynkState { 27 | CONNECTING, 28 | CONNECTED, 29 | DISCONNECTED, 30 | TOKEN_INVALID, 31 | }; 32 | 33 | BlynkProtocol(Transp& transp) 34 | : conn(transp) 35 | , authkey(NULL) 36 | , redir_serv(NULL) 37 | , lastActivityIn(0) 38 | , lastActivityOut(0) 39 | , lastHeartbeat(0) 40 | , msgIdOut(0) 41 | , msgIdOutOverride(0) 42 | , nesting(0) 43 | , state(CONNECTING) 44 | {} 45 | 46 | bool connected() const { return state == CONNECTED; } 47 | 48 | bool isTokenInvalid() const { return state == TOKEN_INVALID; } 49 | 50 | bool connect(uint32_t timeout = BLYNK_TIMEOUT_MS*3) { 51 | conn.disconnect(); 52 | state = CONNECTING; 53 | millis_time_t started = BlynkMillis(); 54 | while ((state != CONNECTED) && 55 | (BlynkMillis() - started < timeout)) 56 | { 57 | run(); 58 | } 59 | return state == CONNECTED; 60 | } 61 | 62 | void disconnect() { 63 | conn.disconnect(); 64 | state = DISCONNECTED; 65 | BLYNK_LOG1(BLYNK_F("Disconnected")); 66 | } 67 | 68 | bool run(bool avail = false); 69 | 70 | // TODO: Fixme 71 | void startSession() { 72 | conn.connect(); 73 | state = CONNECTING; 74 | msgIdOut = 0; 75 | lastHeartbeat = lastActivityIn = lastActivityOut = (BlynkMillis() - 5000UL); 76 | } 77 | 78 | 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); 79 | 80 | void sendResponse(BlynkStatus rsp, uint16_t id = 0) { 81 | sendCmd(BLYNK_CMD_RESPONSE, id, NULL, rsp); 82 | } 83 | 84 | void printBanner() { 85 | #if defined(BLYNK_NO_FANCY_LOGO) 86 | BLYNK_LOG1(BLYNK_F("Blynk v" BLYNK_VERSION " on " BLYNK_INFO_DEVICE 87 | BLYNK_NEWLINE 88 | " #StandWithUkraine https://bit.ly/swua" BLYNK_NEWLINE 89 | BLYNK_NEWLINE 90 | )); 91 | #else 92 | BLYNK_LOG1(BLYNK_F(BLYNK_NEWLINE 93 | " ___ __ __" BLYNK_NEWLINE 94 | " / _ )/ /_ _____ / /__" BLYNK_NEWLINE 95 | " / _ / / // / _ \\/ '_/" BLYNK_NEWLINE 96 | " /____/_/\\_, /_//_/_/\\_\\" BLYNK_NEWLINE 97 | " /___/ v" BLYNK_VERSION " on " BLYNK_INFO_DEVICE BLYNK_NEWLINE 98 | BLYNK_NEWLINE 99 | " #StandWithUkraine https://bit.ly/swua" BLYNK_NEWLINE 100 | BLYNK_NEWLINE 101 | )); 102 | #endif 103 | } 104 | 105 | uint16_t getNextMsgId(); 106 | 107 | private: 108 | 109 | void internalReconnect() { 110 | state = CONNECTING; 111 | conn.disconnect(); 112 | BlynkOnDisconnected(); 113 | } 114 | 115 | int readHeader(BlynkHeader& hdr); 116 | 117 | protected: 118 | void begin(const char* auth) { 119 | this->authkey = auth; 120 | lastHeartbeat = lastActivityIn = lastActivityOut = (BlynkMillis() - 5000UL); 121 | #if !defined(BLYNK_NO_DEFAULT_BANNER) 122 | printBanner(); 123 | #endif 124 | } 125 | 126 | bool processInput(void); 127 | 128 | Transp& conn; 129 | 130 | private: 131 | const char* authkey; 132 | char* redir_serv; 133 | millis_time_t lastActivityIn; 134 | millis_time_t lastActivityOut; 135 | union { 136 | millis_time_t lastHeartbeat; 137 | millis_time_t lastLogin; 138 | }; 139 | uint16_t msgIdOut; 140 | uint16_t msgIdOutOverride; 141 | uint8_t nesting; 142 | BLYNK_MUTEX_DECL(mutex); 143 | protected: 144 | BlynkState state; 145 | }; 146 | 147 | template 148 | bool BlynkProtocol::run(bool avail) 149 | { 150 | BLYNK_RUN_YIELD(); 151 | 152 | if (state == DISCONNECTED) { 153 | return false; 154 | } 155 | 156 | // Detect nesting 157 | BlynkHelperAutoInc guard(nesting); 158 | if (msgIdOutOverride || nesting > 2) { 159 | //BLYNK_LOG1(BLYNK_F("Nested run() skipped")); 160 | return true; 161 | } 162 | 163 | if (conn.connected()) { 164 | while (avail || conn.available() > 0) { 165 | //BLYNK_LOG2(BLYNK_F("Available: "), conn.available()); 166 | //const unsigned long t = micros(); 167 | if (!processInput()) { 168 | conn.disconnect(); 169 | // TODO: Only when in direct mode? 170 | #ifdef BLYNK_USE_DIRECT_CONNECT 171 | state = CONNECTING; 172 | #endif 173 | BlynkOnDisconnected(); 174 | return false; 175 | } 176 | avail = false; 177 | //BLYNK_LOG2(BLYNK_F("Proc time: "), micros() - t); 178 | } 179 | } 180 | 181 | const millis_time_t t = BlynkMillis(); 182 | 183 | // Update connection status after running commands 184 | const bool tconn = conn.connected(); 185 | 186 | if (state == CONNECTED) { 187 | if (!tconn) { 188 | lastHeartbeat = t; 189 | internalReconnect(); 190 | return false; 191 | } 192 | 193 | if (t - lastActivityIn > (1000UL * BLYNK_HEARTBEAT + BLYNK_TIMEOUT_MS*3)) { 194 | #ifdef BLYNK_DEBUG 195 | BLYNK_LOG6(BLYNK_F("Heartbeat timeout: "), t, BLYNK_F(", "), lastActivityIn, BLYNK_F(", "), lastHeartbeat); 196 | #else 197 | BLYNK_LOG1(BLYNK_F("Heartbeat timeout")); 198 | #endif 199 | internalReconnect(); 200 | return false; 201 | } else if ((t - lastActivityIn > 1000UL * BLYNK_HEARTBEAT || 202 | t - lastActivityOut > 1000UL * BLYNK_HEARTBEAT) && 203 | t - lastHeartbeat > BLYNK_TIMEOUT_MS) 204 | { 205 | // Send ping if we didn't either send or receive something 206 | // for BLYNK_HEARTBEAT seconds 207 | sendCmd(BLYNK_CMD_PING); 208 | lastHeartbeat = t; 209 | } 210 | } else if (state == CONNECTING) { 211 | #ifdef BLYNK_USE_DIRECT_CONNECT 212 | if (!tconn) 213 | conn.connect(); 214 | #else 215 | if (tconn && (t - lastLogin > BLYNK_TIMEOUT_MS)) { 216 | BLYNK_LOG1(BLYNK_F("Login timeout")); 217 | conn.disconnect(); 218 | state = CONNECTING; 219 | return false; 220 | } else if (!tconn && (t - lastLogin > 5000UL)) { 221 | conn.disconnect(); 222 | if (!conn.connect()) { 223 | lastLogin = t; 224 | return false; 225 | } 226 | 227 | msgIdOut = 1; 228 | sendCmd(BLYNK_CMD_HW_LOGIN, 1, authkey, strlen(authkey)); 229 | lastLogin = lastActivityOut; 230 | return true; 231 | } 232 | #endif 233 | } 234 | return true; 235 | } 236 | 237 | template 238 | BLYNK_FORCE_INLINE 239 | bool BlynkProtocol::processInput(void) 240 | { 241 | BlynkHeader hdr; 242 | const int ret = readHeader(hdr); 243 | 244 | if (ret == 0) { 245 | return true; // Considered OK (no data on input) 246 | } 247 | 248 | if (ret < 0 || hdr.msg_id == 0) { 249 | #ifdef BLYNK_DEBUG 250 | BLYNK_LOG2(BLYNK_F("Bad hdr len: "), ret); 251 | #endif 252 | return false; 253 | } 254 | 255 | if (hdr.type == BLYNK_CMD_RESPONSE) { 256 | lastActivityIn = BlynkMillis(); 257 | 258 | #ifndef BLYNK_USE_DIRECT_CONNECT 259 | if (state == CONNECTING && (1 == hdr.msg_id)) { 260 | switch (hdr.length) { 261 | case BLYNK_SUCCESS: 262 | case BLYNK_ALREADY_REGISTERED: 263 | BLYNK_LOG3(BLYNK_F("Ready (ping: "), lastActivityIn-lastHeartbeat, BLYNK_F("ms).")); 264 | lastHeartbeat = lastActivityIn; 265 | state = CONNECTED; 266 | #ifdef BLYNK_DEBUG 267 | if (size_t ram = BlynkFreeRam()) { 268 | BLYNK_LOG2(BLYNK_F("Free RAM: "), ram); 269 | } 270 | #endif 271 | this->sendInfo(); 272 | BLYNK_RUN_YIELD(); 273 | BlynkOnConnected(); 274 | return true; 275 | case BLYNK_INVALID_TOKEN: 276 | BLYNK_LOG1(BLYNK_F("Invalid auth token")); 277 | state = TOKEN_INVALID; 278 | break; 279 | default: 280 | BLYNK_LOG2(BLYNK_F("Connect failed. code: "), hdr.length); 281 | } 282 | return false; 283 | } 284 | if (BLYNK_NOT_AUTHENTICATED == hdr.length) { 285 | return false; 286 | } 287 | #endif 288 | // TODO: return code may indicate App presence 289 | return true; 290 | } 291 | 292 | if (hdr.length > BLYNK_MAX_READBYTES) { 293 | BLYNK_LOG2(BLYNK_F("Packet too big: "), hdr.length); 294 | // TODO: Flush 295 | internalReconnect(); 296 | return true; 297 | } 298 | 299 | uint8_t inputBuffer[hdr.length+1]; // Add 1 to zero-terminate 300 | if (hdr.length != conn.read(inputBuffer, hdr.length)) { 301 | #ifdef BLYNK_DEBUG 302 | BLYNK_LOG1(BLYNK_F("Can't read body")); 303 | #endif 304 | return false; 305 | } 306 | inputBuffer[hdr.length] = '\0'; 307 | 308 | BLYNK_DBG_DUMP(">", inputBuffer, hdr.length); 309 | 310 | lastActivityIn = BlynkMillis(); 311 | 312 | switch (hdr.type) 313 | { 314 | case BLYNK_CMD_HW_LOGIN: { 315 | #ifdef BLYNK_USE_DIRECT_CONNECT 316 | if (strncmp(authkey, (char*)inputBuffer, 32)) { 317 | BLYNK_LOG1(BLYNK_F("Invalid token")); 318 | sendResponse(BLYNK_INVALID_TOKEN, hdr.msg_id); 319 | break; 320 | } 321 | #endif 322 | if (state == CONNECTING) { 323 | BLYNK_LOG1(BLYNK_F("Ready")); 324 | state = CONNECTED; 325 | #ifdef BLYNK_DEBUG 326 | if (size_t ram = BlynkFreeRam()) { 327 | BLYNK_LOG2(BLYNK_F("Free RAM: "), ram); 328 | } 329 | #endif 330 | this->sendInfo(); 331 | BLYNK_RUN_YIELD(); 332 | BlynkOnConnected(); 333 | } 334 | sendResponse(BLYNK_SUCCESS, hdr.msg_id); 335 | } break; 336 | case BLYNK_CMD_PING: { 337 | sendResponse(BLYNK_SUCCESS, hdr.msg_id); 338 | } break; 339 | case BLYNK_CMD_REDIRECT: { 340 | if (!redir_serv) { 341 | redir_serv = (char*)malloc(64); 342 | } 343 | BlynkParam param(inputBuffer, hdr.length); 344 | uint16_t redir_port = BLYNK_DEFAULT_PORT; 345 | 346 | BlynkParam::iterator it = param.begin(); 347 | if (it >= param.end()) 348 | return false; 349 | 350 | strncpy(redir_serv, it.asStr(), 64); 351 | redir_serv[63] = '\0'; 352 | 353 | if (++it < param.end()) 354 | redir_port = it.asLong(); 355 | BLYNK_LOG4(BLYNK_F("Redirecting to "), redir_serv, ':', redir_port); 356 | conn.disconnect(); 357 | conn.begin(redir_serv, redir_port); 358 | state = CONNECTING; 359 | lastHeartbeat = lastActivityIn = lastActivityOut = (BlynkMillis() - 5000UL); 360 | } break; 361 | case BLYNK_CMD_HARDWARE: 362 | case BLYNK_CMD_BRIDGE: { 363 | msgIdOutOverride = hdr.msg_id; 364 | this->processCmd(inputBuffer, hdr.length); 365 | msgIdOutOverride = 0; 366 | } break; 367 | case BLYNK_CMD_INTERNAL: { 368 | BlynkReq req = { 0 }; 369 | BlynkParam param(inputBuffer, hdr.length); 370 | BlynkParam::iterator it = param.begin(); 371 | if (it >= param.end()) 372 | return true; 373 | 374 | uint32_t cmd32; 375 | memcpy(&cmd32, it.asStr(), sizeof(cmd32)); 376 | 377 | ++it; 378 | char* start = (char*)(it).asStr(); 379 | unsigned length = hdr.length - (start - (char*)inputBuffer); 380 | BlynkParam param2(start, length); 381 | 382 | msgIdOutOverride = hdr.msg_id; 383 | switch (cmd32) { 384 | case BLYNK_INT_RTC: BlynkWidgetWriteInternalPinRTC(req, param2); break; 385 | case BLYNK_INT_UTC: BlynkWidgetWriteInternalPinUTC(req, param2); break; 386 | case BLYNK_INT_OTA: BlynkWidgetWriteInternalPinOTA(req, param2); break; 387 | case BLYNK_INT_ACON: BlynkWidgetWriteInternalPinACON(req, param2); break; 388 | case BLYNK_INT_ADIS: BlynkWidgetWriteInternalPinADIS(req, param2); break; 389 | case BLYNK_INT_META: BlynkWidgetWriteInternalPinMETA(req, param2); break; 390 | case BLYNK_INT_VFS: BlynkWidgetWriteInternalPinVFS(req, param2); break; 391 | case BLYNK_INT_DBG: BlynkWidgetWriteInternalPinDBG(req, param2); break; 392 | #ifdef BLYNK_DEBUG 393 | default: BLYNK_LOG2(BLYNK_F("Invalid internal cmd:"), param.asStr()); 394 | #endif 395 | } 396 | msgIdOutOverride = 0; 397 | } break; 398 | case BLYNK_CMD_DEBUG_PRINT: { 399 | if (hdr.length) { 400 | BLYNK_LOG2(BLYNK_F("Server: "), (char*)inputBuffer); 401 | } 402 | } break; 403 | default: { 404 | #ifdef BLYNK_DEBUG 405 | BLYNK_LOG2(BLYNK_F("Invalid header type: "), hdr.type); 406 | #endif 407 | // TODO: Flush 408 | internalReconnect(); 409 | } break; 410 | } 411 | 412 | return true; 413 | } 414 | 415 | template 416 | int BlynkProtocol::readHeader(BlynkHeader& hdr) 417 | { 418 | size_t rlen = conn.read(&hdr, sizeof(hdr)); 419 | if (rlen == 0) { 420 | return 0; 421 | } 422 | 423 | if (sizeof(hdr) != rlen) { 424 | return -1; 425 | } 426 | 427 | BLYNK_DBG_DUMP(">", &hdr, sizeof(BlynkHeader)); 428 | 429 | hdr.msg_id = ntohs(hdr.msg_id); 430 | hdr.length = ntohs(hdr.length); 431 | 432 | return rlen; 433 | } 434 | 435 | #ifndef BLYNK_SEND_THROTTLE 436 | #define BLYNK_SEND_THROTTLE 0 437 | #endif 438 | 439 | #ifndef BLYNK_SEND_CHUNK 440 | #define BLYNK_SEND_CHUNK 1024 // Just a big number 441 | #endif 442 | 443 | template 444 | void BlynkProtocol::sendCmd(uint8_t cmd, uint16_t id, const void* data, size_t length, const void* data2, size_t length2) 445 | { 446 | if (!conn.connected() || (cmd != BLYNK_CMD_RESPONSE && cmd != BLYNK_CMD_PING && cmd != BLYNK_CMD_HW_LOGIN && state != CONNECTED) ) { 447 | #ifdef BLYNK_DEBUG_ALL 448 | BLYNK_LOG2(BLYNK_F("Cmd skipped:"), cmd); 449 | #endif 450 | return; 451 | } 452 | 453 | #if defined(BLYNK_MSG_LIMIT) && BLYNK_MSG_LIMIT > 0 454 | if (cmd >= BLYNK_CMD_BRIDGE && cmd <= BLYNK_CMD_HARDWARE) { 455 | const millis_time_t allowed_time = BlynkMax(lastActivityOut, lastActivityIn) + 1000/BLYNK_MSG_LIMIT; 456 | int32_t wait_time = allowed_time - BlynkMillis(); 457 | if (wait_time >= 0) { 458 | #ifdef BLYNK_DEBUG_ALL 459 | BLYNK_LOG2(BLYNK_F("Waiting:"), wait_time); 460 | #endif 461 | while (wait_time >= 0) { 462 | run(); 463 | wait_time = allowed_time - BlynkMillis(); 464 | } 465 | } else if (nesting == 0) { 466 | run(); 467 | } 468 | } 469 | #endif 470 | 471 | BlynkApi< BlynkProtocol >::sendPendingGroup(); 472 | 473 | BLYNK_MUTEX_GUARD(mutex); 474 | 475 | if (0 == id) { 476 | id = getNextMsgId(); 477 | } 478 | 479 | const size_t full_length = (sizeof(BlynkHeader)) + 480 | (data ? length : 0) + 481 | (data2 ? length2 : 0); 482 | 483 | #if defined(BLYNK_SEND_ATOMIC) || defined(ESP8266) || defined(ESP32) || defined(SPARK) || defined(PARTICLE) || defined(ENERGIA) 484 | // Those have more RAM and like single write at a time... 485 | 486 | uint8_t buff[full_length]; 487 | 488 | BlynkHeader* hdr = (BlynkHeader*)buff; 489 | hdr->type = cmd; 490 | hdr->msg_id = htons(id); 491 | hdr->length = htons(length+length2); 492 | 493 | size_t pos = sizeof(BlynkHeader); 494 | if (data && length) { 495 | memcpy(buff + pos, data, length); 496 | pos += length; 497 | } 498 | if (data2 && length2) { 499 | memcpy(buff + pos, data2, length2); 500 | } 501 | 502 | size_t wlen = 0; 503 | while (wlen < full_length) { 504 | const size_t chunk = BlynkMin(size_t(BLYNK_SEND_CHUNK), full_length - wlen); 505 | BLYNK_DBG_DUMP("<", buff + wlen, chunk); 506 | const size_t w = conn.write(buff + wlen, chunk); 507 | BlynkDelay(BLYNK_SEND_THROTTLE); 508 | if (w == 0) { 509 | #ifdef BLYNK_DEBUG 510 | BLYNK_LOG1(BLYNK_F("Cmd error")); 511 | #endif 512 | conn.disconnect(); 513 | state = CONNECTING; 514 | BlynkOnDisconnected(); 515 | return; 516 | } 517 | wlen += w; 518 | } 519 | 520 | #else 521 | 522 | BlynkHeader hdr; 523 | hdr.type = cmd; 524 | hdr.msg_id = htons(id); 525 | hdr.length = htons(length+length2); 526 | 527 | BLYNK_DBG_DUMP("<", &hdr, sizeof(hdr)); 528 | size_t wlen = conn.write(&hdr, sizeof(hdr)); 529 | BlynkDelay(BLYNK_SEND_THROTTLE); 530 | 531 | if (cmd != BLYNK_CMD_RESPONSE) { 532 | if (length) { 533 | BLYNK_DBG_DUMP("<", data, length); 534 | wlen += conn.write(data, length); 535 | BlynkDelay(BLYNK_SEND_THROTTLE); 536 | } 537 | if (length2) { 538 | BLYNK_DBG_DUMP("<", data2, length2); 539 | wlen += conn.write(data2, length2); 540 | BlynkDelay(BLYNK_SEND_THROTTLE); 541 | } 542 | } 543 | 544 | #endif 545 | 546 | if (wlen != full_length) { 547 | #ifdef BLYNK_DEBUG 548 | BLYNK_LOG4(BLYNK_F("Sent "), wlen, '/', full_length); 549 | #endif 550 | internalReconnect(); 551 | return; 552 | } 553 | 554 | lastActivityOut = BlynkMillis(); 555 | 556 | } 557 | 558 | template 559 | uint16_t BlynkProtocol::getNextMsgId() 560 | { 561 | if (msgIdOutOverride != 0) 562 | return msgIdOutOverride; 563 | if (++msgIdOut == 0) 564 | msgIdOut = 1; 565 | return msgIdOut; 566 | } 567 | 568 | #endif 569 | -------------------------------------------------------------------------------- /src/Blynk/BlynkProtocolDefs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkProtocolDefs.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Blynk protocol definitions 8 | * 9 | */ 10 | 11 | #ifndef BlynkProtocolDefs_h 12 | #define BlynkProtocolDefs_h 13 | 14 | enum BlynkCmd 15 | { 16 | BLYNK_CMD_RESPONSE = 0, 17 | 18 | BLYNK_CMD_PING = 6, 19 | 20 | BLYNK_CMD_BRIDGE = 15, 21 | BLYNK_CMD_HARDWARE_SYNC = 16, 22 | BLYNK_CMD_INTERNAL = 17, 23 | BLYNK_CMD_PROPERTY = 19, 24 | BLYNK_CMD_HARDWARE = 20, 25 | BLYNK_CMD_GROUP = 21, 26 | 27 | BLYNK_CMD_HW_LOGIN = 29, 28 | 29 | BLYNK_CMD_REDIRECT = 41, 30 | BLYNK_CMD_DEBUG_PRINT = 55, 31 | BLYNK_CMD_EVENT_LOG = 64, 32 | BLYNK_CMD_EVENT_CLEAR = 65 33 | }; 34 | 35 | enum BlynkStatus 36 | { 37 | BLYNK_SUCCESS = 200, 38 | BLYNK_QUOTA_LIMIT_EXCEPTION = 1, 39 | BLYNK_ILLEGAL_COMMAND = 2, 40 | BLYNK_NOT_REGISTERED = 3, 41 | BLYNK_ALREADY_REGISTERED = 4, 42 | BLYNK_NOT_AUTHENTICATED = 5, 43 | BLYNK_NOT_ALLOWED = 6, 44 | BLYNK_DEVICE_NOT_IN_NETWORK = 7, 45 | BLYNK_NO_ACTIVE_DASHBOARD = 8, 46 | BLYNK_INVALID_TOKEN = 9, 47 | BLYNK_ILLEGAL_COMMAND_BODY = 11, 48 | BLYNK_GET_GRAPH_DATA_EXCEPTION = 12, 49 | BLYNK_NO_DATA_EXCEPTION = 17, 50 | BLYNK_DEVICE_WENT_OFFLINE = 18, 51 | BLYNK_SERVER_EXCEPTION = 19, 52 | 53 | BLYNK_NTF_INVALID_BODY = 13, 54 | BLYNK_NTF_NOT_AUTHORIZED = 14, 55 | BLYNK_NTF_ECXEPTION = 15, 56 | 57 | BLYNK_TIMEOUT = 16, 58 | 59 | BLYNK_NOT_SUPPORTED_VERSION = 20, 60 | BLYNK_ENERGY_LIMIT = 21, 61 | 62 | BLYNK_OPERATION_ACCEPT = 23, 63 | BLYNK_OPERATION_DECLINE = 24, 64 | }; 65 | 66 | struct BlynkHeader 67 | { 68 | uint8_t type; 69 | uint16_t msg_id; 70 | uint16_t length; 71 | } 72 | BLYNK_ATTR_PACKED; 73 | 74 | #if defined(ESP32) || defined(ESP8266) 75 | #include 76 | #elif !defined(htons) && (defined(ARDUINO) || defined(PARTICLE) || defined(__MBED__)) 77 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 78 | #define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) 79 | #define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ 80 | ((x)<< 8 & 0x00FF0000UL) | \ 81 | ((x)>> 8 & 0x0000FF00UL) | \ 82 | ((x)>>24 & 0x000000FFUL) ) 83 | #define ntohs(x) htons(x) 84 | #define ntohl(x) htonl(x) 85 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 86 | #define htons(x) (x) 87 | #define htonl(x) (x) 88 | #define ntohs(x) (x) 89 | #define ntohl(x) (x) 90 | #else 91 | #error "Byte order not defined" 92 | #endif 93 | #endif 94 | 95 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 96 | #define BLYNK_STR_16(a,b) ((uint16_t(a) << 0) | (uint16_t(b) << 8)) 97 | #define BLYNK_STR_32(a,b,c,d) ((uint32_t(a) << 0) | (uint32_t(b) << 8) | (uint32_t(c) << 16) | (uint32_t(d) << 24)) 98 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 99 | #define BLYNK_STR_16(a,b) ((uint16_t(b) << 0) | (uint16_t(a) << 8)) 100 | #define BLYNK_STR_32(a,b,c,d) ((uint32_t(d) << 0) | (uint32_t(c) << 8) | (uint32_t(b) << 16) | (uint32_t(a) << 24)) 101 | #else 102 | #error byte order problem 103 | #endif 104 | 105 | #define BLYNK_HW_PM BLYNK_STR_16('p','m') 106 | #define BLYNK_HW_DW BLYNK_STR_16('d','w') 107 | #define BLYNK_HW_DR BLYNK_STR_16('d','r') 108 | #define BLYNK_HW_AW BLYNK_STR_16('a','w') 109 | #define BLYNK_HW_AR BLYNK_STR_16('a','r') 110 | #define BLYNK_HW_VW BLYNK_STR_16('v','w') 111 | #define BLYNK_HW_VR BLYNK_STR_16('v','r') 112 | 113 | #define BLYNK_INT_RTC BLYNK_STR_32('r','t','c',0) 114 | #define BLYNK_INT_UTC BLYNK_STR_32('u','t','c',0) 115 | #define BLYNK_INT_OTA BLYNK_STR_32('o','t','a',0) 116 | #define BLYNK_INT_VFS BLYNK_STR_32('v','f','s',0) 117 | #define BLYNK_INT_DBG BLYNK_STR_32('d','b','g',0) 118 | #define BLYNK_INT_ACON BLYNK_STR_32('a','c','o','n') 119 | #define BLYNK_INT_ADIS BLYNK_STR_32('a','d','i','s') 120 | #define BLYNK_INT_META BLYNK_STR_32('m','e','t','a') 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /src/Blynk/BlynkTemplates.h: -------------------------------------------------------------------------------- 1 | class BlynkStackOnly 2 | { 3 | protected: 4 | BlynkStackOnly() {} 5 | ~BlynkStackOnly() {} 6 | 7 | private: 8 | /// @brief Declared as private to prevent usage of dynamic memory 9 | void* operator new(size_t size); 10 | /// @brief Declared as private to prevent usage of dynamic memory 11 | void operator delete(void *p); 12 | }; 13 | 14 | class BlynkNonCopyable 15 | { 16 | protected: 17 | BlynkNonCopyable(){} 18 | ~BlynkNonCopyable(){} 19 | 20 | private: 21 | /// @brief Declared as private to prevent usage of copy constructor 22 | BlynkNonCopyable(const BlynkNonCopyable&); 23 | /// @brief Declared as private to prevent usage of assignment operator 24 | BlynkNonCopyable& operator=(const BlynkNonCopyable&); 25 | }; 26 | 27 | template 28 | class BlynkSingleton 29 | : public BlynkNonCopyable 30 | { 31 | public: 32 | /** @brief Returns the instance of the singleton type 33 | When called for the first time, the singleton instance will be 34 | created. All subsequent calls will return a reference to the 35 | previously created instance. 36 | @return The singleton instance 37 | */ 38 | static T* instance() 39 | { 40 | static T instance; 41 | return &instance; 42 | } 43 | protected: 44 | BlynkSingleton() {} 45 | ~BlynkSingleton() {} 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /src/Blynk/BlynkTimer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SimpleTimer.h 3 | * 4 | * SimpleTimer - A timer library for Arduino. 5 | * Author: mromani@ottotecnica.com 6 | * Copyright (c) 2010 OTTOTECNICA Italy 7 | * 8 | * Modifications by Bill Knight 18March2017 9 | * 10 | * This library is free software; you can redistribute it 11 | * and/or modify it under the terms of the GNU Lesser 12 | * General Public License as published by the Free Software 13 | * Foundation; either version 2.1 of the License, or (at 14 | * your option) any later version. 15 | * 16 | * This library is distributed in the hope that it will 17 | * be useful, but WITHOUT ANY WARRANTY; without even the 18 | * implied warranty of MERCHANTABILITY or FITNESS FOR A 19 | * PARTICULAR PURPOSE. See the GNU Lesser General Public 20 | * License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser 23 | * General Public License along with this library; if not, 24 | * write to the Free Software Foundation, Inc., 25 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26 | * 27 | */ 28 | 29 | #ifndef BLYNKTIMER_H 30 | #define BLYNKTIMER_H 31 | 32 | #include 33 | 34 | // Replace SimpleTimer 35 | #define SIMPLETIMER_H 36 | #define SimpleTimer BlynkTimer 37 | 38 | #ifndef BLYNK_MAX_TIMERS 39 | #define BLYNK_MAX_TIMERS 16 40 | #endif 41 | 42 | class SimpleTimer { 43 | #ifdef BLYNK_HAS_FUNCTIONAL_H 44 | typedef std::function timer_callback; 45 | #else 46 | typedef void (*timer_callback)(void); 47 | #endif 48 | typedef void (*timer_callback_p)(void *); 49 | 50 | public: 51 | // maximum number of timers 52 | const static int MAX_TIMERS = BLYNK_MAX_TIMERS; 53 | 54 | // setTimer() constants 55 | const static int RUN_FOREVER = 0; 56 | const static int RUN_ONCE = 1; 57 | 58 | class Handle { 59 | public: 60 | Handle() 61 | : st(NULL), id(-1) 62 | {} 63 | 64 | Handle(SimpleTimer* t, int i) 65 | : st(t), id(i) 66 | {} 67 | 68 | ~Handle() { 69 | } 70 | 71 | operator int() const { 72 | return id; 73 | } 74 | 75 | operator bool() const { 76 | return isValid(); 77 | } 78 | 79 | void operator() (void) const { 80 | if (isValid()) st->executeNow(id); 81 | } 82 | 83 | bool isValid() const { return st && id >= 0; } 84 | void changeInterval(unsigned long d) { 85 | if (isValid()) st->changeInterval(id, d); 86 | } 87 | void deleteTimer() { if (isValid()) st->deleteTimer(id); invalidate(); } 88 | void restartTimer() { if (isValid()) st->restartTimer(id); } 89 | bool isEnabled() { return isValid() && st->isEnabled(id); } 90 | void enable() { if (isValid()) st->enable(id); } 91 | void disable() { if (isValid()) st->disable(id); } 92 | void toggle() { if (isValid()) st->toggle(id); } 93 | 94 | private: 95 | void invalidate() { st = NULL; id = -1; } 96 | 97 | SimpleTimer* st; 98 | int id; 99 | }; 100 | 101 | // constructor 102 | SimpleTimer(); 103 | 104 | void init(); 105 | 106 | // this function must be called inside loop() 107 | void run(); 108 | 109 | // Timer will call function 'f' every 'd' milliseconds forever 110 | // returns the timer number (numTimer) on success or 111 | // -1 on failure (f == NULL) or no free timers 112 | Handle setInterval(unsigned long d, const timer_callback& f) { 113 | return Handle(this, setupTimer(d, f, RUN_FOREVER)); 114 | } 115 | 116 | // Timer will call function 'f' with parameter 'p' every 'd' milliseconds forever 117 | // returns the timer number (numTimer) on success or 118 | // -1 on failure (f == NULL) or no free timers 119 | Handle setInterval(unsigned long d, timer_callback_p f, void* p) { 120 | return Handle(this, setupTimer(d, f, p, RUN_FOREVER)); 121 | } 122 | 123 | // Timer will call function 'f' after 'd' milliseconds one time 124 | // returns the timer number (numTimer) on success or 125 | // -1 on failure (f == NULL) or no free timers 126 | Handle setTimeout(unsigned long d, const timer_callback& f) { 127 | return Handle(this, setupTimer(d, f, RUN_ONCE)); 128 | } 129 | 130 | // Timer will call function 'f' with parameter 'p' after 'd' milliseconds one time 131 | // returns the timer number (numTimer) on success or 132 | // -1 on failure (f == NULL) or no free timers 133 | Handle setTimeout(unsigned long d, timer_callback_p f, void* p) { 134 | return Handle(this, setupTimer(d, f, p, RUN_ONCE)); 135 | } 136 | 137 | // Timer will call function 'f' every 'd' milliseconds 'n' times 138 | // returns the timer number (numTimer) on success or 139 | // -1 on failure (f == NULL) or no free timers 140 | Handle setTimer(unsigned long d, const timer_callback& f, unsigned n) { 141 | return Handle(this, setupTimer(d, f, n)); 142 | } 143 | 144 | // Timer will call function 'f' with parameter 'p' every 'd' milliseconds 'n' times 145 | // returns the timer number (numTimer) on success or 146 | // -1 on failure (f == NULL) or no free timers 147 | Handle setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) { 148 | return Handle(this, setupTimer(d, f, p, n)); 149 | } 150 | 151 | // updates interval of the specified timer 152 | bool changeInterval(unsigned numTimer, unsigned long d); 153 | 154 | // destroy the specified timer 155 | void deleteTimer(unsigned numTimer); 156 | 157 | // restart the specified timer 158 | void restartTimer(unsigned numTimer); 159 | 160 | // remove delay to next execution 161 | void executeNow(unsigned numTimer); 162 | 163 | // returns true if the specified timer is enabled 164 | bool isEnabled(unsigned numTimer); 165 | 166 | // enables the specified timer 167 | void enable(unsigned numTimer); 168 | 169 | // disables the specified timer 170 | void disable(unsigned numTimer); 171 | 172 | // enables all timers 173 | void enableAll(); 174 | 175 | // disables all timers 176 | void disableAll(); 177 | 178 | // enables the specified timer if it's currently disabled, 179 | // and vice-versa 180 | void toggle(unsigned numTimer); 181 | 182 | // returns the number of used timers 183 | unsigned getNumTimers(); 184 | 185 | // returns the number of available timers 186 | unsigned getNumAvailableTimers() { return MAX_TIMERS - numTimers; }; 187 | 188 | private: 189 | // deferred call constants 190 | const static int DEFCALL_DONTRUN = 0; // don't call the callback function 191 | const static int DEFCALL_RUNONLY = 1; // call the callback function but don't delete the timer 192 | const static int DEFCALL_RUNANDDEL = 2; // call the callback function and delete the timer 193 | 194 | // low level function to initialize and enable a new timer 195 | // returns the timer number (numTimer) on success or 196 | // -1 on failure (f == NULL) or no free timers 197 | int setupTimer(unsigned long d, const timer_callback& f, unsigned n); 198 | int setupTimer(unsigned long d, timer_callback_p f, void* p, unsigned n); 199 | 200 | bool isValidTimer(unsigned id) { 201 | return timer[id].callback || timer[id].callback_p; 202 | } 203 | 204 | // find the first available slot 205 | int findFirstFreeSlot(); 206 | 207 | typedef struct { 208 | unsigned long prev_millis; // value returned by the millis() function in the previous run() call 209 | 210 | timer_callback callback; 211 | timer_callback_p callback_p; 212 | 213 | void* param; // function parameter 214 | bool hasParam; // true if callback takes a parameter 215 | unsigned long delay; // delay value 216 | unsigned maxNumRuns; // number of runs to be executed 217 | unsigned numRuns; // number of executed runs 218 | bool enabled; // true if enabled 219 | unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run() 220 | } timer_t; 221 | 222 | timer_t timer[MAX_TIMERS]; 223 | 224 | // actual number of timers in use (-1 means uninitialized) 225 | int numTimers; 226 | }; 227 | 228 | #endif 229 | -------------------------------------------------------------------------------- /src/Blynk/BlynkUtility.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkUtility.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jun 2015 7 | * @brief Utility functions 8 | * 9 | */ 10 | 11 | #ifndef BlynkUtility_h 12 | #define BlynkUtility_h 13 | 14 | #include 15 | 16 | template 17 | const T& BlynkMin(const T& a, const T& b) 18 | { 19 | return (b < a) ? b : a; 20 | } 21 | 22 | template 23 | const T& BlynkMax(const T& a, const T& b) 24 | { 25 | return (b < a) ? a : b; 26 | } 27 | 28 | 29 | template 30 | T BlynkMathMap(T x, T2 in_min, T2 in_max, T2 out_min, T2 out_max) 31 | { 32 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; 33 | } 34 | 35 | template 36 | T BlynkMathClamp(T val, T2 low, T2 high) 37 | { 38 | return (val < low) ? low : ((val > high) ? high : val); 39 | } 40 | 41 | template 42 | T BlynkMathClampMap(T x, T2 in_min, T2 in_max, T2 out_min, T2 out_max) 43 | { 44 | x = BlynkMathClamp(x, in_min, in_max); 45 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; 46 | } 47 | 48 | template 49 | class BlynkMovingAverage { 50 | public: 51 | BlynkMovingAverage() { 52 | reset(); 53 | } 54 | 55 | void reset() { 56 | _first = true; 57 | _avg = 0; 58 | } 59 | 60 | bool hasValue() const { 61 | return !_first; 62 | } 63 | 64 | T get() const { 65 | return _avg; 66 | } 67 | 68 | double getFloat() const { 69 | return _avg; 70 | } 71 | 72 | T push(T value) { 73 | if (_first) { 74 | _avg = value; 75 | _first = false; 76 | } else { 77 | _avg -= _avg/N; 78 | _avg += double(value)/N; 79 | } 80 | return _avg; 81 | } 82 | 83 | private: 84 | bool _first; 85 | double _avg; 86 | }; 87 | 88 | template 89 | void BlynkAverageSample (T& avg, const T& input) { 90 | avg -= avg/WSIZE; 91 | const T add = input/WSIZE; 92 | // Fix for shorter delays 93 | if (add > 0) 94 | avg += add; 95 | else 96 | avg -= 1; 97 | } 98 | 99 | static inline 100 | int BlynkRSSI2SQ(int dBm) { 101 | if(dBm <= -100) { 102 | return 0; 103 | } else if(dBm >= -50) { 104 | return 100; 105 | } else { 106 | return 2 * (dBm + 100); 107 | } 108 | } 109 | 110 | static inline 111 | int BlynkSQ2RSSI(int quality) { 112 | if(quality <= 0) { 113 | return -100; 114 | } else if(quality >= 100) { 115 | return -50; 116 | } else { 117 | return (quality / 2) - 100; 118 | } 119 | } 120 | 121 | static inline 122 | uint32_t BlynkCRC32(const void* data, size_t length, uint32_t previousCrc32 = 0) 123 | { 124 | const uint32_t Polynomial = 0xEDB88320; 125 | uint32_t crc = ~previousCrc32; 126 | unsigned char* current = (unsigned char*)data; 127 | while (length--) { 128 | crc ^= *current++; 129 | for (unsigned int j = 0; j < 8; j++) { 130 | crc = (crc >> 1) ^ (-int(crc & 1) & Polynomial); 131 | } 132 | } 133 | return ~crc; 134 | } 135 | 136 | static inline 137 | bool BlynkStrMatch(const char* pat, const char* txt) { 138 | const long n = strlen(txt); 139 | const long m = strlen(pat); 140 | 141 | if (m == 0) 142 | return (n == 0); 143 | 144 | long i = 0, j = 0, index_txt = -1, 145 | index_pat = -1; 146 | 147 | while (i < n) { 148 | if (j < m && txt[i] == pat[j]) { 149 | i++; 150 | j++; 151 | } else if (j < m && pat[j] == '?') { 152 | i++; 153 | j++; 154 | } else if (j < m && pat[j] == '*') { 155 | index_txt = i; 156 | index_pat = j; 157 | j++; 158 | } else if (index_pat != -1) { 159 | j = index_pat + 1; 160 | i = index_txt + 1; 161 | index_txt++; 162 | } else { 163 | return false; 164 | } 165 | } 166 | 167 | while (j < m && pat[j] == '*') { 168 | j++; 169 | } 170 | 171 | if (j == m) { 172 | return true; 173 | } 174 | 175 | return false; 176 | } 177 | 178 | class BlynkHelperAutoInc { 179 | public: 180 | BlynkHelperAutoInc(uint8_t& counter) : c(counter) { ++c; } 181 | ~BlynkHelperAutoInc() { --c; } 182 | private: 183 | uint8_t& c; 184 | }; 185 | 186 | #define BlynkBitSet(value, bit) ((value) |= (1UL << (bit))) 187 | #define BlynkBitClear(value, bit) ((value) &= ~(1UL << (bit))) 188 | #define BlynkBitRead(value, bit) (((value) >> (bit)) & 0x01) 189 | #define BlynkBitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) 190 | 191 | #endif 192 | -------------------------------------------------------------------------------- /src/Blynk/BlynkWidgetBase.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkWidgetBase.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2016 Volodymyr Shymanskyy 6 | * @date Nov 2016 7 | * @brief 8 | */ 9 | 10 | #ifndef BlynkWidgetBase_h 11 | #define BlynkWidgetBase_h 12 | 13 | #include 14 | 15 | class BlynkWidgetBase 16 | { 17 | public: 18 | BlynkWidgetBase(uint8_t vPin) : mPin(vPin) {} 19 | void setVPin(uint8_t vPin) { mPin = vPin; } 20 | 21 | void onWrite(BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED ¶m) { 22 | BLYNK_LOG1(BLYNK_F("BlynkWidgetBase::onWrite should not be called")); 23 | } 24 | 25 | template 26 | void setLabel(Args... args) { 27 | Blynk.setProperty(mPin, "label", args...); 28 | } 29 | 30 | template 31 | void setColor(Args... args) { 32 | Blynk.setProperty(mPin, "color", args...); 33 | } 34 | 35 | template 36 | void setMin(Args... args) { 37 | Blynk.setProperty(mPin, "min", args...); 38 | } 39 | 40 | template 41 | void setMax(Args... args) { 42 | Blynk.setProperty(mPin, "max", args...); 43 | } 44 | 45 | protected: 46 | uint8_t mPin; 47 | }; 48 | 49 | class BlynkAttachWidgetHelper { 50 | public: 51 | template 52 | explicit BlynkAttachWidgetHelper(T& widget, uint8_t vPin) { 53 | widget.setVPin(vPin); 54 | } 55 | }; 56 | 57 | // Could use __attribute__ ((constructor)), but hope for better portability 58 | #define BLYNK_ATTACH_WIDGET(widget, pin) \ 59 | BlynkAttachWidgetHelper BLYNK_CONCAT2(blnk_widget_helper_, __COUNTER__)((widget), (pin)); \ 60 | BLYNK_WRITE(pin) { (widget).onWrite(request, param); } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/BlynkApiParticle.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkApiParticle.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Mar 2015 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkApiParticle_h 12 | #define BlynkApiParticle_h 13 | 14 | #include "Blynk/BlynkApi.h" 15 | #include "Particle.h" 16 | 17 | template 18 | BLYNK_FORCE_INLINE 19 | void BlynkApi::sendInfo() 20 | { 21 | static const char profile[] BLYNK_PROGMEM = "blnkinf\0" 22 | 23 | // Firmware info 24 | #if defined(BLYNK_NCP_VERSION) 25 | BLYNK_PARAM_KV("ncp" , BLYNK_NCP_VERSION) 26 | #else 27 | BLYNK_PARAM_KV("mcu" , BLYNK_FIRMWARE_VERSION) 28 | #endif 29 | #ifdef BLYNK_FIRMWARE_TYPE 30 | BLYNK_PARAM_KV("fw-type", BLYNK_FIRMWARE_TYPE) 31 | #endif 32 | BLYNK_PARAM_KV("build" , __DATE__ " " __TIME__) 33 | BLYNK_PARAM_KV("blynk" , BLYNK_VERSION) 34 | 35 | // Protocol setup 36 | BLYNK_PARAM_KV("h-beat" , BLYNK_TOSTRING(BLYNK_HEARTBEAT)) 37 | BLYNK_PARAM_KV("buff-in", BLYNK_TOSTRING(BLYNK_MAX_READBYTES)) 38 | 39 | // Additional info 40 | #ifdef BLYNK_INFO_DEVICE 41 | BLYNK_PARAM_KV("dev" , BLYNK_INFO_DEVICE) 42 | #endif 43 | #ifdef BLYNK_INFO_CPU 44 | BLYNK_PARAM_KV("cpu" , BLYNK_INFO_CPU) 45 | #endif 46 | #ifdef BLYNK_INFO_CONNECTION 47 | BLYNK_PARAM_KV("con" , BLYNK_INFO_CONNECTION) 48 | #endif 49 | "\0" 50 | ; 51 | const size_t profile_len = sizeof(profile)-8-2; 52 | 53 | char mem_dyn[64]; 54 | BlynkParam profile_dyn(mem_dyn, 0, sizeof(mem_dyn)); 55 | #ifdef BLYNK_TEMPLATE_ID 56 | { 57 | const char* tmpl = BLYNK_TEMPLATE_ID; 58 | if (tmpl && strlen(tmpl)) { 59 | profile_dyn.add_key("tmpl", tmpl); 60 | } 61 | } 62 | #endif 63 | 64 | #ifdef BLYNK_HAS_PROGMEM 65 | char mem[profile_len]; 66 | memcpy_P(mem, profile+8, profile_len); 67 | static_cast(this)->sendCmd(BLYNK_CMD_INTERNAL, 0, mem, profile_len, profile_dyn.getBuffer(), profile_dyn.getLength()-1); 68 | #else 69 | static_cast(this)->sendCmd(BLYNK_CMD_INTERNAL, 0, profile+8, profile_len, profile_dyn.getBuffer(), profile_dyn.getLength()-1); 70 | #endif 71 | return; 72 | } 73 | 74 | 75 | // Check if analog pins can be referenced by name on this device 76 | #if defined(analogInputToDigitalPin) 77 | #define BLYNK_DECODE_PIN(it) (((it).asStr()[0] == 'A') ? analogInputToDigitalPin(atoi((it).asStr()+1)) : (it).asInt()) 78 | #else 79 | #define BLYNK_DECODE_PIN(it) ((it).asInt()) 80 | 81 | #if defined(BLYNK_DEBUG_ALL) 82 | #pragma message "analogInputToDigitalPin not defined" 83 | #endif 84 | #endif 85 | 86 | template 87 | BLYNK_FORCE_INLINE 88 | void BlynkApi::processCmd(const void* buff, size_t len) 89 | { 90 | BlynkParam param((void*)buff, len); 91 | BlynkParam::iterator it = param.begin(); 92 | if (it >= param.end()) 93 | return; 94 | const char* cmd = it.asStr(); 95 | uint16_t cmd16; 96 | memcpy(&cmd16, cmd, sizeof(cmd16)); 97 | if (++it >= param.end()) 98 | return; 99 | 100 | const uint8_t pin = BLYNK_DECODE_PIN(it); 101 | 102 | switch(cmd16) { 103 | 104 | #ifndef BLYNK_NO_BUILTIN 105 | 106 | case BLYNK_HW_PM: { 107 | while (it < param.end()) { 108 | const uint8_t pin = BLYNK_DECODE_PIN(it); 109 | ++it; 110 | if (!strcmp(it.asStr(), "in")) { 111 | pinMode(pin, INPUT); 112 | } else if (!strcmp(it.asStr(), "out") || !strcmp(it.asStr(), "pwm")) { 113 | pinMode(pin, OUTPUT); 114 | #ifdef INPUT_PULLUP 115 | } else if (!strcmp(it.asStr(), "pu")) { 116 | pinMode(pin, INPUT_PULLUP); 117 | #endif 118 | #ifdef INPUT_PULLDOWN 119 | } else if (!strcmp(it.asStr(), "pd")) { 120 | pinMode(pin, INPUT_PULLDOWN); 121 | #endif 122 | } else { 123 | #ifdef BLYNK_DEBUG 124 | BLYNK_LOG4(BLYNK_F("Invalid pin "), pin, BLYNK_F(" mode "), it.asStr()); 125 | #endif 126 | } 127 | ++it; 128 | } 129 | } break; 130 | case BLYNK_HW_DR: { 131 | char mem[16]; 132 | BlynkParam rsp(mem, 0, sizeof(mem)); 133 | rsp.add("dw"); 134 | rsp.add(pin); 135 | rsp.add(digitalRead(pin)); 136 | static_cast(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, rsp.getBuffer(), rsp.getLength()-1); 137 | } break; 138 | case BLYNK_HW_DW: { 139 | // Should be 1 parameter (value) 140 | if (++it >= param.end()) 141 | return; 142 | 143 | #ifdef ESP8266 144 | // Disable PWM... 145 | analogWrite(pin, 0); 146 | #endif 147 | #ifndef BLYNK_MINIMIZE_PINMODE_USAGE 148 | pinMode(pin, OUTPUT); 149 | #endif 150 | digitalWrite(pin, it.asInt() ? HIGH : LOW); 151 | } break; 152 | case BLYNK_HW_AR: { 153 | char mem[16]; 154 | BlynkParam rsp(mem, 0, sizeof(mem)); 155 | rsp.add("aw"); 156 | rsp.add(pin); 157 | rsp.add(analogRead(pin)); 158 | static_cast(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, rsp.getBuffer(), rsp.getLength()-1); 159 | } break; 160 | case BLYNK_HW_AW: { 161 | // Should be 1 parameter (value) 162 | if (++it >= param.end()) 163 | return; 164 | 165 | #ifndef BLYNK_MINIMIZE_PINMODE_USAGE 166 | pinMode(pin, OUTPUT); 167 | #endif 168 | analogWrite(pin, it.asInt()); 169 | } break; 170 | 171 | #endif 172 | 173 | case BLYNK_HW_VR: { 174 | BlynkReq req = { pin }; 175 | callReadHandler(req); 176 | } break; 177 | case BLYNK_HW_VW: { 178 | ++it; 179 | char* start = (char*)it.asStr(); 180 | BlynkParam param2(start, len - (start - (char*)buff)); 181 | BlynkReq req = { pin }; 182 | callWriteHandler(req, param2); 183 | } break; 184 | default: 185 | BLYNK_LOG2(BLYNK_F("Invalid HW cmd: "), cmd); 186 | static_cast(this)->sendCmd(BLYNK_CMD_RESPONSE, static_cast(this)->msgIdOutOverride, NULL, BLYNK_ILLEGAL_COMMAND); 187 | } 188 | } 189 | 190 | #endif 191 | -------------------------------------------------------------------------------- /src/BlynkMultiClient.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkMultiClient.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2022 Volodymyr Shymanskyy 6 | * @date Oct 2022 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkMultiClient_h 12 | #define BlynkMultiClient_h 13 | 14 | static const char BLYNK_DEFAULT_ROOT_CA[] = 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #ifndef BLYNK_MAX_CLIENT_QTY 22 | #define BLYNK_MAX_CLIENT_QTY 4 23 | #endif 24 | 25 | template 26 | class BlynkArduinoClientMulti 27 | : public BlynkArduinoClientGen 28 | { 29 | struct Entry { 30 | String name; 31 | T* client; 32 | uint16_t port; 33 | }; 34 | public: 35 | BlynkArduinoClientMulti() {} 36 | 37 | void addClient(const String& name, T& c, uint16_t port = BLYNK_DEFAULT_PORT_SSL) { 38 | if (_conn_qty == 0) { 39 | BlynkArduinoClientGen::setClient(&c); 40 | BlynkArduinoClientGen::port = port; 41 | } 42 | if (_conn_qty < BLYNK_MAX_CLIENT_QTY) { 43 | Entry& e = _conn_array[_conn_qty++]; 44 | e.name = name; 45 | e.client = &c; 46 | e.port = port; 47 | } 48 | } 49 | 50 | bool connect() { 51 | for (int i = 0; i < _conn_qty; i++) { 52 | BlynkArduinoClientGen::setClient(_conn_array[i].client); 53 | BlynkArduinoClientGen::port = _conn_array[i].port; 54 | if (BlynkArduinoClientGen::connect()) { 55 | BLYNK_LOG2(_conn_array[i].name, BLYNK_F(" connection OK")); 56 | return true; 57 | } else { 58 | BLYNK_LOG2(_conn_array[i].name, BLYNK_F(" connection failed")); 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | void disconnect() { 65 | BlynkArduinoClientGen::isConn = false; 66 | for (int i = 0; i < _conn_qty; i++) { 67 | _conn_array[i].client->stop(); 68 | } 69 | } 70 | 71 | private: 72 | Entry _conn_array[BLYNK_MAX_CLIENT_QTY]; 73 | int _conn_qty = 0; 74 | }; 75 | 76 | template 77 | class BlynkMultiClient 78 | : public BlynkProtocol 79 | { 80 | typedef BlynkProtocol Base; 81 | public: 82 | BlynkMultiClient(Transport& transp) 83 | : Base(transp) 84 | {} 85 | 86 | template 87 | void addClient(const String& name, T& client, uint16_t port = BLYNK_DEFAULT_PORT_SSL) { 88 | this->conn.addClient(name, client, port); 89 | } 90 | 91 | void config(const char* auth, 92 | const char* domain = BLYNK_DEFAULT_DOMAIN) 93 | { 94 | Base::begin(auth); 95 | this->conn.begin(domain, 0); 96 | } 97 | 98 | void config(const char* auth, 99 | IPAddress ip) 100 | { 101 | Base::begin(auth); 102 | this->conn.begin(ip, 0); 103 | } 104 | 105 | }; 106 | 107 | typedef BlynkArduinoClientMulti BlynkTransport; 108 | 109 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_BLYNK) 110 | static BlynkTransport _blynkTransport; 111 | 112 | BlynkMultiClient Blynk(_blynkTransport); 113 | #else 114 | extern BlynkMultiClient Blynk; 115 | #endif 116 | 117 | #include 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /src/BlynkSimpleParticle.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkSimpleParticle.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Mar 2015 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkSimpleParticle_h 12 | #define BlynkSimpleParticle_h 13 | 14 | #include 15 | 16 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_BLYNK) 17 | static BlynkTransportParticle _blynkTransport; 18 | BlynkParticle Blynk(_blynkTransport); 19 | #else 20 | extern BlynkParticle Blynk; 21 | #endif 22 | 23 | #include "BlynkWidgets.h" 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/BlynkSimpleParticleSSL.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkSimpleParticle.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2022 Volodymyr Shymanskyy 6 | * @date Mar 2022 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkSimpleParticle_h 12 | #define BlynkSimpleParticle_h 13 | 14 | #include 15 | 16 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_BLYNK) 17 | static BlynkTransportParticle _blynkTransport; 18 | BlynkParticle Blynk(_blynkTransport); 19 | #else 20 | extern BlynkParticle Blynk; 21 | #endif 22 | 23 | #include 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/BlynkSimpleSerialBLE.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkSerialBLE.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2016 Volodymyr Shymanskyy 6 | * @date Mar 2016 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkSerialBLE_h 12 | #define BlynkSerialBLE_h 13 | 14 | #ifndef BLYNK_INFO_CONNECTION 15 | #define BLYNK_INFO_CONNECTION "SerialBLE" 16 | #endif 17 | 18 | #define BLYNK_SEND_ATOMIC 19 | #define BLYNK_SEND_CHUNK 20 20 | #define BLYNK_SEND_THROTTLE 40 21 | #define BLYNK_NO_INFO 22 | 23 | #include 24 | 25 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_BLYNK) 26 | BlynkTransportStream _blynkTransport; 27 | BlynkStream Blynk(_blynkTransport); 28 | #else 29 | extern BlynkStream Blynk; 30 | #endif 31 | 32 | #include 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/BlynkSimpleStream.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkSimpleStream.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2016 Volodymyr Shymanskyy 6 | * @date Mar 2016 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef BlynkSimpleStream_h 12 | #define BlynkSimpleStream_h 13 | 14 | #ifndef BLYNK_INFO_CONNECTION 15 | #define BLYNK_INFO_CONNECTION "Stream" 16 | #endif 17 | 18 | #include 19 | 20 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_BLYNK) 21 | BlynkTransportStream _blynkTransport; 22 | BlynkStream Blynk(_blynkTransport); 23 | #else 24 | extern BlynkStream Blynk; 25 | #endif 26 | 27 | #include 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/BlynkWidgets.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkWidgets.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Mar 2015 7 | * @brief 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // Cannot auto-include as these have library dependencies 17 | //#include 18 | 19 | template 20 | class VPinWriteOnChange { 21 | T prev; 22 | const int vpin; 23 | public: 24 | VPinWriteOnChange(int v) 25 | : vpin(v) 26 | {} 27 | 28 | VPinWriteOnChange& operator= (const T& value) { 29 | update(value); 30 | return *this; 31 | } 32 | 33 | void set(const T& value) { 34 | prev = value; 35 | } 36 | 37 | void update(const T& value) { 38 | if (value != prev) { 39 | prev = value; 40 | report(); 41 | } 42 | } 43 | 44 | void report() { 45 | Blynk.virtualWrite(vpin, prev); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /src/WidgetLCD.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WidgetLCD.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Mar 2015 7 | * @brief 8 | */ 9 | 10 | #ifndef WidgetLCD_h 11 | #define WidgetLCD_h 12 | 13 | #include 14 | 15 | class WidgetLCD 16 | : public BlynkWidgetBase 17 | { 18 | public: 19 | WidgetLCD(uint8_t vPin) : BlynkWidgetBase(vPin) {} 20 | 21 | void clear() { 22 | Blynk.virtualWrite(mPin, "clr"); 23 | } 24 | 25 | template 26 | void print(int x, int y, const T& str) { 27 | char mem[BLYNK_MAX_SENDBYTES]; 28 | BlynkParam cmd(mem, 0, sizeof(mem)); 29 | cmd.add("p"); 30 | cmd.add(x); 31 | cmd.add(y); 32 | cmd.add(str); 33 | Blynk.virtualWrite(mPin, cmd); 34 | } 35 | 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/WidgetLED.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WidgetLED.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Apr 2015 7 | * @brief 8 | */ 9 | 10 | #ifndef WidgetLED_h 11 | #define WidgetLED_h 12 | 13 | #include 14 | 15 | class WidgetLED 16 | : public BlynkWidgetBase 17 | { 18 | public: 19 | WidgetLED(uint8_t vPin) 20 | : BlynkWidgetBase(vPin) 21 | , mValue(0) 22 | {} 23 | 24 | uint8_t getValue() const { 25 | return mValue; 26 | } 27 | 28 | void setValue(uint8_t value) { 29 | mValue = value; 30 | Blynk.virtualWrite(mPin, value); 31 | } 32 | 33 | void on() { 34 | setValue(255); 35 | } 36 | 37 | void off() { 38 | setValue(0); 39 | } 40 | 41 | private: 42 | uint8_t mValue; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/WidgetMap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WidgetMap.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2016 Volodymyr Shymanskyy 6 | * @date Nov 2016 7 | * @brief 8 | */ 9 | 10 | #ifndef WidgetMap_h 11 | #define WidgetMap_h 12 | 13 | #include 14 | 15 | class WidgetMap 16 | : public BlynkWidgetBase 17 | { 18 | public: 19 | WidgetMap(uint8_t vPin) : BlynkWidgetBase(vPin) {} 20 | 21 | void clear() { 22 | Blynk.virtualWrite(mPin, "clr"); 23 | } 24 | 25 | template 26 | void location(const T1& index, const T2& lat, const T3& lon, const T4& value) { 27 | Blynk.virtualWrite(mPin, index, lat, lon, value); 28 | } 29 | 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/WidgetTerminal.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WidgetTerminal.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief 8 | */ 9 | 10 | #ifndef WidgetTerminal_h 11 | #define WidgetTerminal_h 12 | 13 | #ifndef BLYNK_TERMINAL_BUFF_OUT 14 | #define BLYNK_TERMINAL_BUFF_OUT 250 15 | #endif 16 | #ifndef BLYNK_TERMINAL_BUFF_IN 17 | #define BLYNK_TERMINAL_BUFF_IN BLYNK_MAX_READBYTES 18 | #endif 19 | 20 | #if defined(ARDUINO) && !(defined(LINUX) || defined(__MBED__)) 21 | #define BLYNK_USE_STREAM_CLASS 22 | #elif defined(SPARK) || defined(PARTICLE) 23 | #define BLYNK_USE_STREAM_CLASS 24 | #endif 25 | 26 | #include 27 | #include 28 | 29 | #ifdef BLYNK_USE_STREAM_CLASS 30 | #include 31 | #endif 32 | 33 | class WidgetTerminal 34 | : public BlynkWidgetBase 35 | #ifdef BLYNK_USE_STREAM_CLASS 36 | , public Stream 37 | #endif 38 | { 39 | public: 40 | WidgetTerminal(uint8_t vPin = -1) 41 | : BlynkWidgetBase(vPin) 42 | , mOutQty(0) 43 | {} 44 | 45 | virtual ~WidgetTerminal() {} 46 | 47 | /* 48 | * Writing 49 | */ 50 | 51 | virtual size_t write(uint8_t byte) { 52 | mOutBuf[mOutQty++] = byte; 53 | if (byte == '\n' && Blynk.connected()) { 54 | flush(); 55 | } 56 | if (mOutQty >= sizeof(mOutBuf)) { 57 | flush(); 58 | } 59 | return 1; 60 | } 61 | 62 | virtual void flush() { 63 | if (mOutQty) { 64 | Blynk.virtualWriteBinary(mPin, mOutBuf, mOutQty); 65 | mOutQty = 0; 66 | } 67 | } 68 | 69 | /* 70 | * Reading 71 | */ 72 | 73 | virtual int read() { return mRxBuff.readable() ? mRxBuff.get() : -1; } 74 | virtual int available() { return mRxBuff.size(); } 75 | virtual int peek() { return mRxBuff.readable() ? mRxBuff.peek() : -1; } 76 | 77 | void process(const BlynkParam& param) { 78 | mRxBuff.put((uint8_t*)param.getBuffer(), param.getLength()); 79 | 80 | if (mAppendCR) { mRxBuff.put('\r'); } 81 | if (mAppendLF) { mRxBuff.put('\n'); } 82 | } 83 | 84 | void onWrite(BlynkReq BLYNK_UNUSED &request, const BlynkParam& param) { 85 | process(param); 86 | } 87 | 88 | /* 89 | * Extra 90 | */ 91 | 92 | void clear() { 93 | mOutQty = 0; 94 | Blynk.virtualWrite(mPin, "clr"); 95 | } 96 | 97 | // Append '\r' on input 98 | void autoAppendCR(bool v = true) { 99 | mAppendCR = v; 100 | } 101 | 102 | // Append '\n' on input 103 | void autoAppendLF(bool v = true) { 104 | mAppendLF = v; 105 | } 106 | 107 | #ifdef BLYNK_USE_STREAM_CLASS 108 | 109 | using Stream::write; 110 | 111 | virtual size_t write(const void* buff, size_t len) { 112 | return write((char*)buff, len); 113 | } 114 | 115 | #else 116 | 117 | virtual size_t write(const void* buff, size_t len) { 118 | uint8_t* buf = (uint8_t*)buff; 119 | size_t left = len; 120 | while (left--) { 121 | write(*buf++); 122 | } 123 | return len; 124 | } 125 | 126 | virtual size_t write(const char* str) { 127 | return write(str, strlen(str)); 128 | } 129 | 130 | #endif 131 | 132 | private: 133 | typedef BlynkFifo InputFifo; 134 | 135 | bool mAppendCR = false; 136 | bool mAppendLF = false; 137 | InputFifo mRxBuff; 138 | 139 | uint8_t mOutBuf[BLYNK_TERMINAL_BUFF_OUT]; 140 | unsigned mOutQty; 141 | }; 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /src/WidgetTimeInput.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file WidgetTimeInput.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Aug 2016 7 | * @brief 8 | * 9 | */ 10 | 11 | #ifndef WidgetTimeInput_h 12 | #define WidgetTimeInput_h 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | class TimeInputParam 19 | { 20 | public: 21 | enum TimeMode { 22 | TIME_UNDEFINED, 23 | TIME_SUNSET, 24 | TIME_SUNRISE, 25 | TIME_SPECIFIED 26 | }; 27 | 28 | TimeInputParam(const BlynkParam& param) 29 | { 30 | mStartMode = TIME_UNDEFINED; 31 | mStopMode = TIME_UNDEFINED; 32 | mTZ[0] = '\0'; 33 | mWeekdays = -1; // All set 34 | mTZ_Offset = 0; 35 | 36 | BlynkParam::iterator it = param.begin(); 37 | if (it >= param.end()) 38 | return; 39 | 40 | if (0 == strcmp(it.asStr(), "sr")) { 41 | mStartMode = TIME_SUNRISE; 42 | } else if (0 == strcmp(it.asStr(), "ss")) { 43 | mStartMode = TIME_SUNSET; 44 | } else if (!it.isEmpty()) { 45 | mStart = BlynkTime(it.asLong()); 46 | if (mStart.isValid()) { 47 | mStartMode = TIME_SPECIFIED; 48 | } 49 | } 50 | 51 | if (++it >= param.end()) 52 | return; 53 | 54 | if (0 == strcmp(it.asStr(), "sr")) { 55 | mStopMode = TIME_SUNRISE; 56 | } else if (0 == strcmp(it.asStr(), "ss")) { 57 | mStopMode = TIME_SUNSET; 58 | } else if (!it.isEmpty()) { 59 | mStop = BlynkTime(it.asLong()); 60 | if (mStop.isValid()) { 61 | mStopMode = TIME_SPECIFIED; 62 | } 63 | } 64 | 65 | if (++it >= param.end()) 66 | return; 67 | 68 | strncpy(mTZ, it.asStr(), sizeof(mTZ)); 69 | 70 | if (++it >= param.end()) 71 | return; 72 | 73 | if (!it.isEmpty()) { 74 | mWeekdays = 0; 75 | const char* p = it.asStr(); 76 | 77 | while (int c = *p++) { 78 | if (c >= '1' && c <= '7') { 79 | BlynkBitSet(mWeekdays, c - '1'); 80 | } 81 | } 82 | } 83 | 84 | if (++it >= param.end()) 85 | return; 86 | 87 | mTZ_Offset = it.asLong(); 88 | } 89 | 90 | BlynkTime& getStart() { return mStart; } 91 | BlynkTime& getStop() { return mStop; } 92 | 93 | TimeMode getStartMode() const { return mStartMode; } 94 | TimeMode getStopMode() const { return mStopMode; } 95 | 96 | bool hasStartTime() const { return mStartMode == TIME_SPECIFIED; } 97 | bool isStartSunrise() const { return mStartMode == TIME_SUNRISE; } 98 | bool isStartSunset() const { return mStartMode == TIME_SUNSET; } 99 | int getStartHour() const { return mStart.hour(); } 100 | int getStartMinute() const { return mStart.minute(); } 101 | int getStartSecond() const { return mStart.second(); } 102 | 103 | bool hasStopTime() const { return mStopMode == TIME_SPECIFIED; } 104 | bool isStopSunrise() const { return mStopMode == TIME_SUNRISE; } 105 | bool isStopSunset() const { return mStopMode == TIME_SUNSET; } 106 | int getStopHour() const { return mStop.hour(); } 107 | int getStopMinute() const { return mStop.minute(); } 108 | int getStopSecond() const { return mStop.second(); } 109 | 110 | const char* getTZ() const { return mTZ; } 111 | int32_t getTZ_Offset() const { return mTZ_Offset; } 112 | 113 | bool isWeekdaySelected(int day) const { 114 | return BlynkBitRead(mWeekdays, (day - 1) % 7); 115 | } 116 | 117 | private: 118 | BlynkTime mStart; 119 | BlynkTime mStop; 120 | char mTZ[32]; 121 | int32_t mTZ_Offset; 122 | 123 | TimeMode mStopMode; 124 | TimeMode mStartMode; 125 | 126 | uint8_t mWeekdays; 127 | }; 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /src/blynk.cpp: -------------------------------------------------------------------------------- 1 | // We don't use this cpp file... 2 | -------------------------------------------------------------------------------- /src/blynk.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Blynk.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Nov 2016 7 | * @brief 8 | * 9 | */ 10 | 11 | #include "BlynkSimpleParticle.h" 12 | 13 | -------------------------------------------------------------------------------- /src/utility/BlynkDateTime.h: -------------------------------------------------------------------------------- 1 | 2 | #warning "Please include Blynk/BlynkDateTime.h, instead of utility/BlynkDateTime.h" 3 | #include 4 | -------------------------------------------------------------------------------- /src/utility/BlynkDebug.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkDebug.cpp 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Debug utilities for Arduino 8 | */ 9 | #include 10 | 11 | #if defined(ARDUINO) && defined(__AVR__) && defined(BLYNK_USE_AVR_WDT) 12 | 13 | #include 14 | #include 15 | 16 | BLYNK_CONSTRUCTOR 17 | static void BlynkSystemInit() 18 | { 19 | MCUSR = 0; 20 | wdt_disable(); 21 | } 22 | 23 | void BlynkReset() 24 | { 25 | wdt_enable(WDTO_15MS); 26 | delay(50); 27 | void(*resetFunc)(void) = 0; 28 | resetFunc(); 29 | for(;;) {} // To make compiler happy 30 | } 31 | 32 | size_t BlynkFreeRam() 33 | { 34 | extern int __heap_start, *__brkval; 35 | int v; 36 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 37 | } 38 | 39 | #define _BLYNK_USE_DEFAULT_MILLIS 40 | #define _BLYNK_USE_DEFAULT_DELAY 41 | 42 | #elif defined(ARDUINO) && defined(__AVR__) 43 | 44 | #include 45 | 46 | void BlynkReset() 47 | { 48 | void(*resetFunc)(void) = 0; 49 | resetFunc(); 50 | for(;;) {} 51 | } 52 | 53 | size_t BlynkFreeRam() 54 | { 55 | extern int __heap_start, *__brkval; 56 | int v; 57 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 58 | } 59 | 60 | #define _BLYNK_USE_DEFAULT_MILLIS 61 | #define _BLYNK_USE_DEFAULT_DELAY 62 | 63 | #elif defined(ARDUINO) && (defined(ESP8266) || defined(ESP32)) 64 | 65 | #include 66 | 67 | size_t BlynkFreeRam() 68 | { 69 | return ESP.getFreeHeap(); 70 | } 71 | 72 | void BlynkReset() 73 | { 74 | ESP.restart(); 75 | for(;;) {} 76 | } 77 | 78 | #define _BLYNK_USE_DEFAULT_MILLIS 79 | #define _BLYNK_USE_DEFAULT_DELAY 80 | 81 | #elif defined(ARDUINO_ARCH_RP2040) && !defined(__MBED__) 82 | 83 | #include 84 | 85 | void BlynkReset() 86 | { 87 | rp2040.reboot(); 88 | for(;;) {} 89 | } 90 | 91 | #define _BLYNK_USE_DEFAULT_FREE_RAM 92 | #define _BLYNK_USE_DEFAULT_MILLIS 93 | #define _BLYNK_USE_DEFAULT_DELAY 94 | 95 | #elif defined(ARDUINO_ARCH_SAMD) || \ 96 | defined(ARDUINO_ARCH_SAM) || \ 97 | defined(ARDUINO_ARCH_NRF5) 98 | 99 | #include 100 | 101 | extern "C" char *sbrk(int i); 102 | 103 | size_t BlynkFreeRam() 104 | { 105 | char stack_dummy = 0; 106 | return &stack_dummy - sbrk(0); 107 | } 108 | 109 | void BlynkReset() 110 | { 111 | NVIC_SystemReset(); 112 | for(;;) {} 113 | } 114 | 115 | #define _BLYNK_USE_DEFAULT_MILLIS 116 | #define _BLYNK_USE_DEFAULT_DELAY 117 | 118 | #elif defined (ARDUINO_ARCH_ARC32) 119 | 120 | millis_time_t BlynkMillis() 121 | { 122 | // TODO: Remove workaround for Intel Curie 123 | // https://forum.arduino.cc/index.php?topic=391836.0 124 | noInterrupts(); 125 | uint64_t t = millis(); 126 | interrupts(); 127 | return t; 128 | } 129 | 130 | #define _BLYNK_USE_DEFAULT_FREE_RAM 131 | #define _BLYNK_USE_DEFAULT_RESET 132 | #define _BLYNK_USE_DEFAULT_DELAY 133 | 134 | #elif defined(ARDUINO) && (defined(__STM32F1__) || defined(__STM32F3__)) 135 | 136 | #include 137 | #include 138 | 139 | void BlynkReset() 140 | { 141 | nvic_sys_reset(); 142 | for(;;) {} 143 | } 144 | 145 | #define _BLYNK_USE_DEFAULT_FREE_RAM 146 | #define _BLYNK_USE_DEFAULT_MILLIS 147 | #define _BLYNK_USE_DEFAULT_DELAY 148 | 149 | #elif defined (PARTICLE) || defined(SPARK) 150 | 151 | #include "application.h" 152 | 153 | void BlynkReset() 154 | { 155 | System.reset(); 156 | for(;;) {} // To make compiler happy 157 | } 158 | 159 | #define _BLYNK_USE_DEFAULT_FREE_RAM 160 | #define _BLYNK_USE_DEFAULT_MILLIS 161 | #define _BLYNK_USE_DEFAULT_DELAY 162 | 163 | #elif defined(__MBED__) && !defined(ARDUINO) 164 | 165 | #include "mbed.h" 166 | 167 | static Timer blynk_millis_timer; 168 | static Ticker blynk_waker; 169 | 170 | static 171 | void blynk_wake() { 172 | //pc.puts("(...)"); 173 | } 174 | 175 | BLYNK_CONSTRUCTOR 176 | static void BlynkSystemInit() 177 | { 178 | blynk_waker.attach(&blynk_wake, 2.0); 179 | blynk_millis_timer.start(); 180 | } 181 | 182 | void BlynkDelay(millis_time_t ms) 183 | { 184 | wait_ms(ms); 185 | } 186 | 187 | millis_time_t BlynkMillis() 188 | { 189 | return blynk_millis_timer.read_ms(); 190 | } 191 | 192 | #define _BLYNK_USE_DEFAULT_FREE_RAM 193 | #define _BLYNK_USE_DEFAULT_RESET 194 | 195 | #elif defined(LINUX) && defined(RASPBERRY) 196 | 197 | #include 198 | #include 199 | 200 | BLYNK_CONSTRUCTOR 201 | static void BlynkSystemInit() 202 | { 203 | wiringPiSetupGpio(); 204 | } 205 | 206 | void BlynkReset() 207 | { 208 | exit(1); 209 | for(;;) {} // To make compiler happy 210 | } 211 | 212 | #define _BLYNK_USE_DEFAULT_FREE_RAM 213 | #define _BLYNK_USE_DEFAULT_MILLIS 214 | #define _BLYNK_USE_DEFAULT_DELAY 215 | 216 | #elif defined(LINUX) 217 | 218 | #define _POSIX_C_SOURCE 200809L 219 | #include 220 | #include 221 | #include 222 | 223 | static millis_time_t blynk_startup_time = 0; 224 | 225 | BLYNK_CONSTRUCTOR 226 | static void BlynkSystemInit() 227 | { 228 | blynk_startup_time = BlynkMillis(); 229 | } 230 | 231 | void BlynkReset() 232 | { 233 | exit(1); 234 | for(;;) {} // To make compiler happy 235 | } 236 | 237 | void BlynkDelay(millis_time_t ms) 238 | { 239 | usleep(ms * 1000); 240 | } 241 | 242 | millis_time_t BlynkMillis() 243 | { 244 | struct timespec ts; 245 | clock_gettime(CLOCK_MONOTONIC, &ts ); 246 | return ( ts.tv_sec * 1000 + ts.tv_nsec / 1000000L ) - blynk_startup_time; 247 | } 248 | 249 | #define _BLYNK_USE_DEFAULT_FREE_RAM 250 | 251 | #elif defined(TI_CC3220) 252 | 253 | #include 254 | #include 255 | #include 256 | #include 257 | 258 | #include 259 | 260 | #include 261 | #include 262 | #include 263 | 264 | void BlynkReset() 265 | { 266 | sl_Stop(200); 267 | for(;;) { 268 | PRCMHibernateCycleTrigger(); 269 | } 270 | } 271 | 272 | void BlynkDelay(millis_time_t ms) 273 | { 274 | usleep(ms * 1000); 275 | } 276 | 277 | millis_time_t BlynkMillis() 278 | { 279 | return Clock_getTicks(); 280 | } 281 | 282 | #define _BLYNK_USE_DEFAULT_FREE_RAM 283 | 284 | #else 285 | 286 | #if defined(BLYNK_DEBUG_ALL) 287 | #warning "Need to implement board-specific utilities" 288 | #endif 289 | 290 | #define _BLYNK_USE_DEFAULT_FREE_RAM 291 | #define _BLYNK_USE_DEFAULT_RESET 292 | #define _BLYNK_USE_DEFAULT_MILLIS 293 | #define _BLYNK_USE_DEFAULT_DELAY 294 | 295 | #endif 296 | 297 | #ifdef _BLYNK_USE_DEFAULT_DELAY 298 | void BlynkDelay(millis_time_t ms) 299 | { 300 | return delay(ms); 301 | } 302 | #endif 303 | 304 | #ifdef _BLYNK_USE_DEFAULT_MILLIS 305 | millis_time_t BlynkMillis() 306 | { 307 | return millis(); 308 | } 309 | #endif 310 | 311 | #ifdef _BLYNK_USE_DEFAULT_FREE_RAM 312 | size_t BlynkFreeRam() 313 | { 314 | return 0; 315 | } 316 | #endif 317 | 318 | #ifdef _BLYNK_USE_DEFAULT_RESET 319 | void BlynkReset() 320 | { 321 | for(;;) {} // To make compiler happy 322 | } 323 | #endif 324 | 325 | #ifdef _BLYNK_USE_DEFAULT_RESET 326 | bool BlynkResetImplemented() { return false; } 327 | #else 328 | bool BlynkResetImplemented() { return true; } 329 | #endif 330 | 331 | void BlynkFatal() 332 | { 333 | BlynkDelay(10000L); 334 | BlynkReset(); 335 | } 336 | 337 | -------------------------------------------------------------------------------- /src/utility/BlynkFifo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkFifo.h 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Feb 2015 7 | * @brief FIFO implementation 8 | * 9 | */ 10 | 11 | #ifndef BlynkFifo_h 12 | #define BlynkFifo_h 13 | 14 | #include 15 | 16 | template 17 | class BlynkFifo 18 | { 19 | public: 20 | BlynkFifo() 21 | { 22 | clear(); 23 | } 24 | 25 | void clear() 26 | { 27 | _r = 0; 28 | _w = 0; 29 | } 30 | 31 | ~BlynkFifo(void) 32 | {} 33 | 34 | // writing thread/context API 35 | //------------------------------------------------------------- 36 | 37 | bool writeable(void) 38 | { 39 | return free() > 0; 40 | } 41 | 42 | int free(void) 43 | { 44 | int s = _r - _w; 45 | if (s <= 0) 46 | s += N; 47 | return s - 1; 48 | } 49 | 50 | T put(const T& c) 51 | { 52 | int i = _w; 53 | int j = i; 54 | i = _inc(i); 55 | while (i == _r) // = !writeable() 56 | /* nothing / just wait */; 57 | _b[j] = c; 58 | _w = i; 59 | return c; 60 | } 61 | 62 | int put(const T* p, int n, bool blocking = false) 63 | { 64 | int c = n; 65 | while (c) 66 | { 67 | int f; 68 | while ((f = free()) == 0) // wait for space 69 | { 70 | if (!blocking) return n - c; // no more space and not blocking 71 | /* nothing / just wait */; 72 | } 73 | // check free space 74 | if (c < f) f = c; 75 | int w = _w; 76 | int m = N - w; 77 | // check wrap 78 | if (f > m) f = m; 79 | memcpy(&_b[w], p, f); 80 | _w = _inc(w, f); 81 | c -= f; 82 | p += f; 83 | } 84 | return n - c; 85 | } 86 | 87 | // reading thread/context API 88 | // -------------------------------------------------------- 89 | 90 | bool readable(void) 91 | { 92 | return (_r != _w); 93 | } 94 | 95 | size_t size(void) 96 | { 97 | int s = _w - _r; 98 | if (s < 0) 99 | s += N; 100 | return s; 101 | } 102 | 103 | T get(void) 104 | { 105 | int r = _r; 106 | while (r == _w) // = !readable() 107 | /* nothing / just wait */; 108 | T t = _b[r]; 109 | _r = _inc(r); 110 | return t; 111 | } 112 | 113 | T peek(void) 114 | { 115 | int r = _r; 116 | while (r == _w); 117 | return _b[r]; 118 | } 119 | 120 | int get(T* p, int n, bool blocking = false) 121 | { 122 | int c = n; 123 | while (c) 124 | { 125 | int f; 126 | for (;;) // wait for data 127 | { 128 | f = size(); 129 | if (f) break; // free space 130 | if (!blocking) return n - c; // no space and not blocking 131 | /* nothing / just wait */; 132 | } 133 | // check available data 134 | if (c < f) f = c; 135 | int r = _r; 136 | int m = N - r; 137 | // check wrap 138 | if (f > m) f = m; 139 | memcpy(p, &_b[r], f); 140 | _r = _inc(r, f); 141 | c -= f; 142 | p += f; 143 | } 144 | return n - c; 145 | } 146 | 147 | private: 148 | int _inc(int i, int n = 1) 149 | { 150 | return (i + n) % N; 151 | } 152 | 153 | T _b[N]; 154 | volatile int _w; 155 | volatile int _r; 156 | }; 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /src/utility/BlynkHandlers.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file BlynkHandlers.cpp 3 | * @author Volodymyr Shymanskyy 4 | * @license This project is released under the MIT License (MIT) 5 | * @copyright Copyright (c) 2015 Volodymyr Shymanskyy 6 | * @date Jan 2015 7 | * @brief Virtual pin utilities 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | void BlynkNoOpCbk() 15 | {} 16 | 17 | void BlynkWidgetRead(BlynkReq BLYNK_UNUSED &request) 18 | { 19 | BLYNK_LOG2(BLYNK_F("No handler for reading from pin "), request.pin); 20 | } 21 | 22 | void BlynkWidgetWrite(BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED ¶m) 23 | { 24 | BLYNK_LOG2(BLYNK_F("No handler for writing to pin "), request.pin); 25 | } 26 | 27 | #define BLYNK_ON_READ_IMPL(pin) void BlynkWidgetRead ## pin (BlynkReq BLYNK_UNUSED &req) \ 28 | __attribute__((weak, alias("BlynkWidgetRead"))) 29 | 30 | #define BLYNK_ON_WRITE_IMPL(pin) void BlynkWidgetWrite ## pin (BlynkReq BLYNK_UNUSED &req, const BlynkParam BLYNK_UNUSED ¶m) \ 31 | __attribute__((weak, alias("BlynkWidgetWrite"))) 32 | 33 | BLYNK_CONNECTED() __attribute__((weak, alias("BlynkNoOpCbk"))); 34 | BLYNK_DISCONNECTED() __attribute__((weak, alias("BlynkNoOpCbk"))); 35 | 36 | // Internal Virtual Pins 37 | BLYNK_ON_WRITE_IMPL(InternalPinACON); 38 | BLYNK_ON_WRITE_IMPL(InternalPinADIS); 39 | BLYNK_ON_WRITE_IMPL(InternalPinRTC); 40 | BLYNK_ON_WRITE_IMPL(InternalPinUTC); 41 | BLYNK_ON_WRITE_IMPL(InternalPinOTA); 42 | BLYNK_ON_WRITE_IMPL(InternalPinMETA); 43 | BLYNK_ON_WRITE_IMPL(InternalPinVFS); 44 | BLYNK_ON_WRITE_IMPL(InternalPinDBG); 45 | 46 | // Regular Virtual Pins 47 | BLYNK_ON_READ_IMPL(Default); 48 | BLYNK_ON_WRITE_IMPL(Default); 49 | 50 | BLYNK_ON_READ_IMPL(0 ); 51 | BLYNK_ON_READ_IMPL(1 ); 52 | BLYNK_ON_READ_IMPL(2 ); 53 | BLYNK_ON_READ_IMPL(3 ); 54 | BLYNK_ON_READ_IMPL(4 ); 55 | BLYNK_ON_READ_IMPL(5 ); 56 | BLYNK_ON_READ_IMPL(6 ); 57 | BLYNK_ON_READ_IMPL(7 ); 58 | BLYNK_ON_READ_IMPL(8 ); 59 | BLYNK_ON_READ_IMPL(9 ); 60 | BLYNK_ON_READ_IMPL(10); 61 | BLYNK_ON_READ_IMPL(11); 62 | BLYNK_ON_READ_IMPL(12); 63 | BLYNK_ON_READ_IMPL(13); 64 | BLYNK_ON_READ_IMPL(14); 65 | BLYNK_ON_READ_IMPL(15); 66 | BLYNK_ON_READ_IMPL(16); 67 | BLYNK_ON_READ_IMPL(17); 68 | BLYNK_ON_READ_IMPL(18); 69 | BLYNK_ON_READ_IMPL(19); 70 | BLYNK_ON_READ_IMPL(20); 71 | BLYNK_ON_READ_IMPL(21); 72 | BLYNK_ON_READ_IMPL(22); 73 | BLYNK_ON_READ_IMPL(23); 74 | BLYNK_ON_READ_IMPL(24); 75 | BLYNK_ON_READ_IMPL(25); 76 | BLYNK_ON_READ_IMPL(26); 77 | BLYNK_ON_READ_IMPL(27); 78 | BLYNK_ON_READ_IMPL(28); 79 | BLYNK_ON_READ_IMPL(29); 80 | BLYNK_ON_READ_IMPL(30); 81 | BLYNK_ON_READ_IMPL(31); 82 | #ifdef BLYNK_USE_128_VPINS 83 | BLYNK_ON_READ_IMPL(32); 84 | BLYNK_ON_READ_IMPL(33); 85 | BLYNK_ON_READ_IMPL(34); 86 | BLYNK_ON_READ_IMPL(35); 87 | BLYNK_ON_READ_IMPL(36); 88 | BLYNK_ON_READ_IMPL(37); 89 | BLYNK_ON_READ_IMPL(38); 90 | BLYNK_ON_READ_IMPL(39); 91 | BLYNK_ON_READ_IMPL(40); 92 | BLYNK_ON_READ_IMPL(41); 93 | BLYNK_ON_READ_IMPL(42); 94 | BLYNK_ON_READ_IMPL(43); 95 | BLYNK_ON_READ_IMPL(44); 96 | BLYNK_ON_READ_IMPL(45); 97 | BLYNK_ON_READ_IMPL(46); 98 | BLYNK_ON_READ_IMPL(47); 99 | BLYNK_ON_READ_IMPL(48); 100 | BLYNK_ON_READ_IMPL(49); 101 | BLYNK_ON_READ_IMPL(50); 102 | BLYNK_ON_READ_IMPL(51); 103 | BLYNK_ON_READ_IMPL(52); 104 | BLYNK_ON_READ_IMPL(53); 105 | BLYNK_ON_READ_IMPL(54); 106 | BLYNK_ON_READ_IMPL(55); 107 | BLYNK_ON_READ_IMPL(56); 108 | BLYNK_ON_READ_IMPL(57); 109 | BLYNK_ON_READ_IMPL(58); 110 | BLYNK_ON_READ_IMPL(59); 111 | BLYNK_ON_READ_IMPL(60); 112 | BLYNK_ON_READ_IMPL(61); 113 | BLYNK_ON_READ_IMPL(62); 114 | BLYNK_ON_READ_IMPL(63); 115 | BLYNK_ON_READ_IMPL(64); 116 | BLYNK_ON_READ_IMPL(65); 117 | BLYNK_ON_READ_IMPL(66); 118 | BLYNK_ON_READ_IMPL(67); 119 | BLYNK_ON_READ_IMPL(68); 120 | BLYNK_ON_READ_IMPL(69); 121 | BLYNK_ON_READ_IMPL(70); 122 | BLYNK_ON_READ_IMPL(71); 123 | BLYNK_ON_READ_IMPL(72); 124 | BLYNK_ON_READ_IMPL(73); 125 | BLYNK_ON_READ_IMPL(74); 126 | BLYNK_ON_READ_IMPL(75); 127 | BLYNK_ON_READ_IMPL(76); 128 | BLYNK_ON_READ_IMPL(77); 129 | BLYNK_ON_READ_IMPL(78); 130 | BLYNK_ON_READ_IMPL(79); 131 | BLYNK_ON_READ_IMPL(80); 132 | BLYNK_ON_READ_IMPL(81); 133 | BLYNK_ON_READ_IMPL(82); 134 | BLYNK_ON_READ_IMPL(83); 135 | BLYNK_ON_READ_IMPL(84); 136 | BLYNK_ON_READ_IMPL(85); 137 | BLYNK_ON_READ_IMPL(86); 138 | BLYNK_ON_READ_IMPL(87); 139 | BLYNK_ON_READ_IMPL(88); 140 | BLYNK_ON_READ_IMPL(89); 141 | BLYNK_ON_READ_IMPL(90); 142 | BLYNK_ON_READ_IMPL(91); 143 | BLYNK_ON_READ_IMPL(92); 144 | BLYNK_ON_READ_IMPL(93); 145 | BLYNK_ON_READ_IMPL(94); 146 | BLYNK_ON_READ_IMPL(95); 147 | BLYNK_ON_READ_IMPL(96); 148 | BLYNK_ON_READ_IMPL(97); 149 | BLYNK_ON_READ_IMPL(98); 150 | BLYNK_ON_READ_IMPL(99); 151 | BLYNK_ON_READ_IMPL(100); 152 | BLYNK_ON_READ_IMPL(101); 153 | BLYNK_ON_READ_IMPL(102); 154 | BLYNK_ON_READ_IMPL(103); 155 | BLYNK_ON_READ_IMPL(104); 156 | BLYNK_ON_READ_IMPL(105); 157 | BLYNK_ON_READ_IMPL(106); 158 | BLYNK_ON_READ_IMPL(107); 159 | BLYNK_ON_READ_IMPL(108); 160 | BLYNK_ON_READ_IMPL(109); 161 | BLYNK_ON_READ_IMPL(110); 162 | BLYNK_ON_READ_IMPL(111); 163 | BLYNK_ON_READ_IMPL(112); 164 | BLYNK_ON_READ_IMPL(113); 165 | BLYNK_ON_READ_IMPL(114); 166 | BLYNK_ON_READ_IMPL(115); 167 | BLYNK_ON_READ_IMPL(116); 168 | BLYNK_ON_READ_IMPL(117); 169 | BLYNK_ON_READ_IMPL(118); 170 | BLYNK_ON_READ_IMPL(119); 171 | BLYNK_ON_READ_IMPL(120); 172 | BLYNK_ON_READ_IMPL(121); 173 | BLYNK_ON_READ_IMPL(122); 174 | BLYNK_ON_READ_IMPL(123); 175 | BLYNK_ON_READ_IMPL(124); 176 | BLYNK_ON_READ_IMPL(125); 177 | BLYNK_ON_READ_IMPL(126); 178 | BLYNK_ON_READ_IMPL(127); 179 | #endif 180 | 181 | BLYNK_ON_WRITE_IMPL(0 ); 182 | BLYNK_ON_WRITE_IMPL(1 ); 183 | BLYNK_ON_WRITE_IMPL(2 ); 184 | BLYNK_ON_WRITE_IMPL(3 ); 185 | BLYNK_ON_WRITE_IMPL(4 ); 186 | BLYNK_ON_WRITE_IMPL(5 ); 187 | BLYNK_ON_WRITE_IMPL(6 ); 188 | BLYNK_ON_WRITE_IMPL(7 ); 189 | BLYNK_ON_WRITE_IMPL(8 ); 190 | BLYNK_ON_WRITE_IMPL(9 ); 191 | BLYNK_ON_WRITE_IMPL(10); 192 | BLYNK_ON_WRITE_IMPL(11); 193 | BLYNK_ON_WRITE_IMPL(12); 194 | BLYNK_ON_WRITE_IMPL(13); 195 | BLYNK_ON_WRITE_IMPL(14); 196 | BLYNK_ON_WRITE_IMPL(15); 197 | BLYNK_ON_WRITE_IMPL(16); 198 | BLYNK_ON_WRITE_IMPL(17); 199 | BLYNK_ON_WRITE_IMPL(18); 200 | BLYNK_ON_WRITE_IMPL(19); 201 | BLYNK_ON_WRITE_IMPL(20); 202 | BLYNK_ON_WRITE_IMPL(21); 203 | BLYNK_ON_WRITE_IMPL(22); 204 | BLYNK_ON_WRITE_IMPL(23); 205 | BLYNK_ON_WRITE_IMPL(24); 206 | BLYNK_ON_WRITE_IMPL(25); 207 | BLYNK_ON_WRITE_IMPL(26); 208 | BLYNK_ON_WRITE_IMPL(27); 209 | BLYNK_ON_WRITE_IMPL(28); 210 | BLYNK_ON_WRITE_IMPL(29); 211 | BLYNK_ON_WRITE_IMPL(30); 212 | BLYNK_ON_WRITE_IMPL(31); 213 | #ifdef BLYNK_USE_128_VPINS 214 | BLYNK_ON_WRITE_IMPL(32); 215 | BLYNK_ON_WRITE_IMPL(33); 216 | BLYNK_ON_WRITE_IMPL(34); 217 | BLYNK_ON_WRITE_IMPL(35); 218 | BLYNK_ON_WRITE_IMPL(36); 219 | BLYNK_ON_WRITE_IMPL(37); 220 | BLYNK_ON_WRITE_IMPL(38); 221 | BLYNK_ON_WRITE_IMPL(39); 222 | BLYNK_ON_WRITE_IMPL(40); 223 | BLYNK_ON_WRITE_IMPL(41); 224 | BLYNK_ON_WRITE_IMPL(42); 225 | BLYNK_ON_WRITE_IMPL(43); 226 | BLYNK_ON_WRITE_IMPL(44); 227 | BLYNK_ON_WRITE_IMPL(45); 228 | BLYNK_ON_WRITE_IMPL(46); 229 | BLYNK_ON_WRITE_IMPL(47); 230 | BLYNK_ON_WRITE_IMPL(48); 231 | BLYNK_ON_WRITE_IMPL(49); 232 | BLYNK_ON_WRITE_IMPL(50); 233 | BLYNK_ON_WRITE_IMPL(51); 234 | BLYNK_ON_WRITE_IMPL(52); 235 | BLYNK_ON_WRITE_IMPL(53); 236 | BLYNK_ON_WRITE_IMPL(54); 237 | BLYNK_ON_WRITE_IMPL(55); 238 | BLYNK_ON_WRITE_IMPL(56); 239 | BLYNK_ON_WRITE_IMPL(57); 240 | BLYNK_ON_WRITE_IMPL(58); 241 | BLYNK_ON_WRITE_IMPL(59); 242 | BLYNK_ON_WRITE_IMPL(60); 243 | BLYNK_ON_WRITE_IMPL(61); 244 | BLYNK_ON_WRITE_IMPL(62); 245 | BLYNK_ON_WRITE_IMPL(63); 246 | BLYNK_ON_WRITE_IMPL(64); 247 | BLYNK_ON_WRITE_IMPL(65); 248 | BLYNK_ON_WRITE_IMPL(66); 249 | BLYNK_ON_WRITE_IMPL(67); 250 | BLYNK_ON_WRITE_IMPL(68); 251 | BLYNK_ON_WRITE_IMPL(69); 252 | BLYNK_ON_WRITE_IMPL(70); 253 | BLYNK_ON_WRITE_IMPL(71); 254 | BLYNK_ON_WRITE_IMPL(72); 255 | BLYNK_ON_WRITE_IMPL(73); 256 | BLYNK_ON_WRITE_IMPL(74); 257 | BLYNK_ON_WRITE_IMPL(75); 258 | BLYNK_ON_WRITE_IMPL(76); 259 | BLYNK_ON_WRITE_IMPL(77); 260 | BLYNK_ON_WRITE_IMPL(78); 261 | BLYNK_ON_WRITE_IMPL(79); 262 | BLYNK_ON_WRITE_IMPL(80); 263 | BLYNK_ON_WRITE_IMPL(81); 264 | BLYNK_ON_WRITE_IMPL(82); 265 | BLYNK_ON_WRITE_IMPL(83); 266 | BLYNK_ON_WRITE_IMPL(84); 267 | BLYNK_ON_WRITE_IMPL(85); 268 | BLYNK_ON_WRITE_IMPL(86); 269 | BLYNK_ON_WRITE_IMPL(87); 270 | BLYNK_ON_WRITE_IMPL(88); 271 | BLYNK_ON_WRITE_IMPL(89); 272 | BLYNK_ON_WRITE_IMPL(90); 273 | BLYNK_ON_WRITE_IMPL(91); 274 | BLYNK_ON_WRITE_IMPL(92); 275 | BLYNK_ON_WRITE_IMPL(93); 276 | BLYNK_ON_WRITE_IMPL(94); 277 | BLYNK_ON_WRITE_IMPL(95); 278 | BLYNK_ON_WRITE_IMPL(96); 279 | BLYNK_ON_WRITE_IMPL(97); 280 | BLYNK_ON_WRITE_IMPL(98); 281 | BLYNK_ON_WRITE_IMPL(99); 282 | BLYNK_ON_WRITE_IMPL(100); 283 | BLYNK_ON_WRITE_IMPL(101); 284 | BLYNK_ON_WRITE_IMPL(102); 285 | BLYNK_ON_WRITE_IMPL(103); 286 | BLYNK_ON_WRITE_IMPL(104); 287 | BLYNK_ON_WRITE_IMPL(105); 288 | BLYNK_ON_WRITE_IMPL(106); 289 | BLYNK_ON_WRITE_IMPL(107); 290 | BLYNK_ON_WRITE_IMPL(108); 291 | BLYNK_ON_WRITE_IMPL(109); 292 | BLYNK_ON_WRITE_IMPL(110); 293 | BLYNK_ON_WRITE_IMPL(111); 294 | BLYNK_ON_WRITE_IMPL(112); 295 | BLYNK_ON_WRITE_IMPL(113); 296 | BLYNK_ON_WRITE_IMPL(114); 297 | BLYNK_ON_WRITE_IMPL(115); 298 | BLYNK_ON_WRITE_IMPL(116); 299 | BLYNK_ON_WRITE_IMPL(117); 300 | BLYNK_ON_WRITE_IMPL(118); 301 | BLYNK_ON_WRITE_IMPL(119); 302 | BLYNK_ON_WRITE_IMPL(120); 303 | BLYNK_ON_WRITE_IMPL(121); 304 | BLYNK_ON_WRITE_IMPL(122); 305 | BLYNK_ON_WRITE_IMPL(123); 306 | BLYNK_ON_WRITE_IMPL(124); 307 | BLYNK_ON_WRITE_IMPL(125); 308 | BLYNK_ON_WRITE_IMPL(126); 309 | BLYNK_ON_WRITE_IMPL(127); 310 | #endif 311 | 312 | static const WidgetReadHandler BlynkReadHandlerVector[] BLYNK_PROGMEM = { 313 | BlynkWidgetRead0, BlynkWidgetRead1, BlynkWidgetRead2, BlynkWidgetRead3, 314 | BlynkWidgetRead4, BlynkWidgetRead5, BlynkWidgetRead6, BlynkWidgetRead7, 315 | BlynkWidgetRead8, BlynkWidgetRead9, BlynkWidgetRead10, BlynkWidgetRead11, 316 | BlynkWidgetRead12, BlynkWidgetRead13, BlynkWidgetRead14, BlynkWidgetRead15, 317 | BlynkWidgetRead16, BlynkWidgetRead17, BlynkWidgetRead18, BlynkWidgetRead19, 318 | BlynkWidgetRead20, BlynkWidgetRead21, BlynkWidgetRead22, BlynkWidgetRead23, 319 | BlynkWidgetRead24, BlynkWidgetRead25, BlynkWidgetRead26, BlynkWidgetRead27, 320 | BlynkWidgetRead28, BlynkWidgetRead29, BlynkWidgetRead30, BlynkWidgetRead31, 321 | #ifdef BLYNK_USE_128_VPINS 322 | BlynkWidgetRead32, BlynkWidgetRead33, BlynkWidgetRead34, BlynkWidgetRead35, 323 | BlynkWidgetRead36, BlynkWidgetRead37, BlynkWidgetRead38, BlynkWidgetRead39, 324 | BlynkWidgetRead40, BlynkWidgetRead41, BlynkWidgetRead42, BlynkWidgetRead43, 325 | BlynkWidgetRead44, BlynkWidgetRead45, BlynkWidgetRead46, BlynkWidgetRead47, 326 | BlynkWidgetRead48, BlynkWidgetRead49, BlynkWidgetRead50, BlynkWidgetRead51, 327 | BlynkWidgetRead52, BlynkWidgetRead53, BlynkWidgetRead54, BlynkWidgetRead55, 328 | BlynkWidgetRead56, BlynkWidgetRead57, BlynkWidgetRead58, BlynkWidgetRead59, 329 | BlynkWidgetRead60, BlynkWidgetRead61, BlynkWidgetRead62, BlynkWidgetRead63, 330 | BlynkWidgetRead64, BlynkWidgetRead65, BlynkWidgetRead66, BlynkWidgetRead67, 331 | BlynkWidgetRead68, BlynkWidgetRead69, BlynkWidgetRead70, BlynkWidgetRead71, 332 | BlynkWidgetRead72, BlynkWidgetRead73, BlynkWidgetRead74, BlynkWidgetRead75, 333 | BlynkWidgetRead76, BlynkWidgetRead77, BlynkWidgetRead78, BlynkWidgetRead79, 334 | BlynkWidgetRead80, BlynkWidgetRead81, BlynkWidgetRead82, BlynkWidgetRead83, 335 | BlynkWidgetRead84, BlynkWidgetRead85, BlynkWidgetRead86, BlynkWidgetRead87, 336 | BlynkWidgetRead88, BlynkWidgetRead89, BlynkWidgetRead90, BlynkWidgetRead91, 337 | BlynkWidgetRead92, BlynkWidgetRead93, BlynkWidgetRead94, BlynkWidgetRead95, 338 | BlynkWidgetRead96, BlynkWidgetRead97, BlynkWidgetRead98, BlynkWidgetRead99, 339 | BlynkWidgetRead100, BlynkWidgetRead101, BlynkWidgetRead102, BlynkWidgetRead103, 340 | BlynkWidgetRead104, BlynkWidgetRead105, BlynkWidgetRead106, BlynkWidgetRead107, 341 | BlynkWidgetRead108, BlynkWidgetRead109, BlynkWidgetRead110, BlynkWidgetRead111, 342 | BlynkWidgetRead112, BlynkWidgetRead113, BlynkWidgetRead114, BlynkWidgetRead115, 343 | BlynkWidgetRead116, BlynkWidgetRead117, BlynkWidgetRead118, BlynkWidgetRead119, 344 | BlynkWidgetRead120, BlynkWidgetRead121, BlynkWidgetRead122, BlynkWidgetRead123, 345 | BlynkWidgetRead124, BlynkWidgetRead125, BlynkWidgetRead126, BlynkWidgetRead127, 346 | #endif 347 | }; 348 | 349 | static const WidgetWriteHandler BlynkWriteHandlerVector[] BLYNK_PROGMEM = { 350 | BlynkWidgetWrite0, BlynkWidgetWrite1, BlynkWidgetWrite2, BlynkWidgetWrite3, 351 | BlynkWidgetWrite4, BlynkWidgetWrite5, BlynkWidgetWrite6, BlynkWidgetWrite7, 352 | BlynkWidgetWrite8, BlynkWidgetWrite9, BlynkWidgetWrite10, BlynkWidgetWrite11, 353 | BlynkWidgetWrite12, BlynkWidgetWrite13, BlynkWidgetWrite14, BlynkWidgetWrite15, 354 | BlynkWidgetWrite16, BlynkWidgetWrite17, BlynkWidgetWrite18, BlynkWidgetWrite19, 355 | BlynkWidgetWrite20, BlynkWidgetWrite21, BlynkWidgetWrite22, BlynkWidgetWrite23, 356 | BlynkWidgetWrite24, BlynkWidgetWrite25, BlynkWidgetWrite26, BlynkWidgetWrite27, 357 | BlynkWidgetWrite28, BlynkWidgetWrite29, BlynkWidgetWrite30, BlynkWidgetWrite31, 358 | #ifdef BLYNK_USE_128_VPINS 359 | BlynkWidgetWrite32, BlynkWidgetWrite33, BlynkWidgetWrite34, BlynkWidgetWrite35, 360 | BlynkWidgetWrite36, BlynkWidgetWrite37, BlynkWidgetWrite38, BlynkWidgetWrite39, 361 | BlynkWidgetWrite40, BlynkWidgetWrite41, BlynkWidgetWrite42, BlynkWidgetWrite43, 362 | BlynkWidgetWrite44, BlynkWidgetWrite45, BlynkWidgetWrite46, BlynkWidgetWrite47, 363 | BlynkWidgetWrite48, BlynkWidgetWrite49, BlynkWidgetWrite50, BlynkWidgetWrite51, 364 | BlynkWidgetWrite52, BlynkWidgetWrite53, BlynkWidgetWrite54, BlynkWidgetWrite55, 365 | BlynkWidgetWrite56, BlynkWidgetWrite57, BlynkWidgetWrite58, BlynkWidgetWrite59, 366 | BlynkWidgetWrite60, BlynkWidgetWrite61, BlynkWidgetWrite62, BlynkWidgetWrite63, 367 | BlynkWidgetWrite64, BlynkWidgetWrite65, BlynkWidgetWrite66, BlynkWidgetWrite67, 368 | BlynkWidgetWrite68, BlynkWidgetWrite69, BlynkWidgetWrite70, BlynkWidgetWrite71, 369 | BlynkWidgetWrite72, BlynkWidgetWrite73, BlynkWidgetWrite74, BlynkWidgetWrite75, 370 | BlynkWidgetWrite76, BlynkWidgetWrite77, BlynkWidgetWrite78, BlynkWidgetWrite79, 371 | BlynkWidgetWrite80, BlynkWidgetWrite81, BlynkWidgetWrite82, BlynkWidgetWrite83, 372 | BlynkWidgetWrite84, BlynkWidgetWrite85, BlynkWidgetWrite86, BlynkWidgetWrite87, 373 | BlynkWidgetWrite88, BlynkWidgetWrite89, BlynkWidgetWrite90, BlynkWidgetWrite91, 374 | BlynkWidgetWrite92, BlynkWidgetWrite93, BlynkWidgetWrite94, BlynkWidgetWrite95, 375 | BlynkWidgetWrite96, BlynkWidgetWrite97, BlynkWidgetWrite98, BlynkWidgetWrite99, 376 | BlynkWidgetWrite100, BlynkWidgetWrite101, BlynkWidgetWrite102, BlynkWidgetWrite103, 377 | BlynkWidgetWrite104, BlynkWidgetWrite105, BlynkWidgetWrite106, BlynkWidgetWrite107, 378 | BlynkWidgetWrite108, BlynkWidgetWrite109, BlynkWidgetWrite110, BlynkWidgetWrite111, 379 | BlynkWidgetWrite112, BlynkWidgetWrite113, BlynkWidgetWrite114, BlynkWidgetWrite115, 380 | BlynkWidgetWrite116, BlynkWidgetWrite117, BlynkWidgetWrite118, BlynkWidgetWrite119, 381 | BlynkWidgetWrite120, BlynkWidgetWrite121, BlynkWidgetWrite122, BlynkWidgetWrite123, 382 | BlynkWidgetWrite124, BlynkWidgetWrite125, BlynkWidgetWrite126, BlynkWidgetWrite127, 383 | #endif 384 | }; 385 | 386 | WidgetReadHandler GetReadHandler(uint8_t pin) 387 | { 388 | if (pin >= BLYNK_COUNT_OF(BlynkReadHandlerVector)) 389 | return NULL; 390 | #ifdef BLYNK_HAS_PROGMEM 391 | return (WidgetReadHandler)pgm_read_word(&BlynkReadHandlerVector[pin]); 392 | #else 393 | return BlynkReadHandlerVector[pin]; 394 | #endif 395 | } 396 | 397 | WidgetWriteHandler GetWriteHandler(uint8_t pin) 398 | { 399 | if (pin >= BLYNK_COUNT_OF(BlynkWriteHandlerVector)) 400 | return NULL; 401 | #ifdef BLYNK_HAS_PROGMEM 402 | return (WidgetWriteHandler)pgm_read_word(&BlynkWriteHandlerVector[pin]); 403 | #else 404 | return BlynkWriteHandlerVector[pin]; 405 | #endif 406 | } 407 | -------------------------------------------------------------------------------- /src/utility/BlynkHelpers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #if !defined(BLYNK_NO_FLOAT) && defined(BLYNK_USE_INTERNAL_DTOSTRF) 7 | 8 | #include 9 | #include 10 | 11 | char* dtostrf_internal(double number, signed char BLYNK_UNUSED width, unsigned char prec, char *s) { 12 | if(isnan(number)) { 13 | strcpy(s, "nan"); 14 | return s; 15 | } 16 | if(isinf(number)) { 17 | strcpy(s, "inf"); 18 | return s; 19 | } 20 | 21 | if(number > 4294967040.0 || number < -4294967040.0) { 22 | strcpy(s, "ovf"); 23 | return s; 24 | } 25 | char* out = s; 26 | // Handle negative numbers 27 | if(number < 0.0) { 28 | *out = '-'; 29 | ++out; 30 | number = -number; 31 | } 32 | 33 | // Round correctly so that print(1.999, 2) prints as "2.00" 34 | double rounding = 0.5; 35 | for(uint8_t i = 0; i < prec; ++i) { 36 | rounding /= 10.0; 37 | } 38 | 39 | number += rounding; 40 | 41 | // Extract the integer part of the number and print it 42 | unsigned long int_part = (unsigned long) number; 43 | double remainder = number - (double) int_part; 44 | out += sprintf(out, "%lu", int_part); 45 | 46 | // Print the decimal point, but only if there are digits beyond 47 | if(prec > 0) { 48 | *out++ = '.'; 49 | } 50 | 51 | while(prec-- > 0) { 52 | remainder *= 10.0; 53 | if((int)remainder == 0) { 54 | *out++ = '0'; 55 | } 56 | } 57 | if((int)remainder != 0) { 58 | sprintf(out, "%d", (int)remainder); 59 | } else { 60 | *out++ = '\0'; 61 | } 62 | 63 | return s; 64 | } 65 | 66 | #endif 67 | 68 | #if !defined(BLYNK_NO_LONGLONG) && defined(BLYNK_USE_INTERNAL_ATOLL) 69 | 70 | long long atoll_internal(const char *instr) 71 | { 72 | long long retval = 0; 73 | for (; *instr; instr++) { 74 | retval = 10*retval + (*instr - '0'); 75 | } 76 | return retval; 77 | } 78 | 79 | #endif 80 | 81 | #if !defined(BLYNK_NO_LONGLONG) 82 | 83 | char* lltoa_internal(long long val, char* buf, unsigned buf_len, int base) 84 | { 85 | int i = buf_len-2; 86 | int sign = (val < 0); 87 | buf[buf_len-1] = '\0'; 88 | 89 | if (val == 0) { 90 | buf[i] = '0'; 91 | return &buf[i]; 92 | } 93 | 94 | unsigned long long absval = sign ? -val : val; 95 | 96 | for (; absval && i ; --i, absval /= base) { 97 | buf[i] = "0123456789abcdef"[absval % base]; 98 | } 99 | 100 | if (sign) { buf[i--] = '-'; } 101 | 102 | return &buf[i+1]; 103 | } 104 | 105 | char* ulltoa_internal(unsigned long long val, char* buf, unsigned buf_len, int base) 106 | { 107 | int i = buf_len-2; 108 | buf[buf_len-1] = '\0'; 109 | 110 | if (val == 0) { 111 | buf[i] = '0'; 112 | return &buf[i]; 113 | } 114 | 115 | for (; val && i ; --i, val /= base) { 116 | buf[i] = "0123456789abcdef"[val % base]; 117 | } 118 | 119 | return &buf[i+1]; 120 | } 121 | 122 | #endif 123 | 124 | -------------------------------------------------------------------------------- /src/utility/BlynkStreamMulti.h: -------------------------------------------------------------------------------- 1 | #ifndef BlynkStreamMulti_h 2 | #define BlynkStreamMulti_h 3 | 4 | #ifndef BLYNK_MULTI_STREAM_MAX_QTY 5 | #define BLYNK_MULTI_STREAM_MAX_QTY 6 6 | #endif 7 | 8 | class MultiStream 9 | : public Stream 10 | { 11 | public: 12 | MultiStream() {} 13 | virtual ~MultiStream() {} 14 | 15 | bool addStream(Stream* stream) { 16 | if (stream && _streamsQty < BLYNK_MULTI_STREAM_MAX_QTY) { 17 | _streams[_streamsQty++] = stream; 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | bool addStream(Stream& stream) { 24 | return addStream(&stream); 25 | } 26 | 27 | /* 28 | * Writing 29 | */ 30 | 31 | virtual size_t write(uint8_t ch) { 32 | for (int i=0; i<_streamsQty; i++) { 33 | _streams[i]->write(ch); 34 | } 35 | return 1; 36 | } 37 | 38 | virtual void flush() { 39 | for (int i=0; i<_streamsQty; i++) { 40 | return _streams[i]->flush(); 41 | } 42 | } 43 | 44 | /* 45 | * Reading 46 | */ 47 | 48 | virtual int available() { 49 | for (int i=0; i<_streamsQty; i++) { 50 | int avail = _streams[i]->available(); 51 | if (avail > 0) { return avail; } 52 | } 53 | return 0; 54 | } 55 | 56 | virtual int read() { 57 | for (int i=0; i<_streamsQty; i++) { 58 | if (_streams[i]->available()) { 59 | return _streams[i]->read(); 60 | } 61 | } 62 | return -1; 63 | } 64 | 65 | virtual int peek() { 66 | for (int i=0; i<_streamsQty; i++) { 67 | if (_streams[i]->available()) { 68 | return _streams[i]->peek(); 69 | } 70 | } 71 | return -1; 72 | } 73 | 74 | private: 75 | Stream* _streams[BLYNK_MULTI_STREAM_MAX_QTY]; 76 | int _streamsQty = 0; 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/utility/BlynkStreamNull.h: -------------------------------------------------------------------------------- 1 | #ifndef BlynkStreamNull_h 2 | #define BlynkStreamNull_h 3 | 4 | class NullStream 5 | : public Stream 6 | { 7 | public: 8 | 9 | /* 10 | * Writing 11 | */ 12 | 13 | virtual size_t write(uint8_t) override { 14 | return 1; 15 | } 16 | 17 | virtual size_t write(const uint8_t* buffer, size_t size) override { 18 | (void)buffer; 19 | (void)size; 20 | return size; 21 | } 22 | 23 | virtual int availableForWrite() { 24 | return 4096; 25 | } 26 | 27 | virtual void flush() {} 28 | 29 | /* 30 | * Reading 31 | */ 32 | 33 | virtual int available() override { 34 | return 0; 35 | } 36 | 37 | virtual int read() override { 38 | return -1; 39 | } 40 | 41 | virtual int peek() override { 42 | return -1; 43 | } 44 | 45 | virtual size_t readBytes(char* buffer, size_t len) { 46 | (void)buffer; 47 | (void)len; 48 | return 0; 49 | } 50 | 51 | virtual int read(uint8_t* buffer, size_t len) { 52 | (void)buffer; 53 | (void)len; 54 | return 0; 55 | } 56 | }; 57 | 58 | #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_NULLSTREAM) 59 | static NullStream NullStream; 60 | #endif 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/utility/BlynkTimeUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #define YEAR_0 1900 7 | #define YEAR_EPOCH 1970 8 | #define SECS_IN_DAY (24L * 60L * 60L) 9 | #define IS_LEAP_YEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) 10 | #define YEAR_DAYS(year) (IS_LEAP_YEAR(year) ? 366 : 365) 11 | 12 | #define TIME_MAX 2147483647L 13 | 14 | static const int month_tab[2][12] = { 15 | { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, 16 | { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } 17 | }; 18 | 19 | struct blynk_tm* blynk_gmtime_r(const blynk_time_t* t, struct blynk_tm *tm) 20 | { 21 | blynk_time_t time = *t; 22 | unsigned long dayclock, dayno; 23 | int year = YEAR_EPOCH; 24 | 25 | dayclock = (unsigned long) time % SECS_IN_DAY; 26 | dayno = (unsigned long) time / SECS_IN_DAY; 27 | 28 | tm->tm_sec = dayclock % 60; 29 | tm->tm_min = (dayclock % 3600) / 60; 30 | tm->tm_hour = dayclock / 3600; 31 | tm->tm_wday = (dayno + 4) % 7; 32 | while (dayno >= (unsigned long) YEAR_DAYS(year)) { 33 | dayno -= YEAR_DAYS(year); 34 | year++; 35 | } 36 | tm->tm_year = year - YEAR_0; 37 | tm->tm_yday = dayno; 38 | tm->tm_mon = 0; 39 | while (dayno >= (unsigned long) month_tab[IS_LEAP_YEAR(year)][tm->tm_mon]) { 40 | dayno -= month_tab[IS_LEAP_YEAR(year)][tm->tm_mon]; 41 | tm->tm_mon++; 42 | } 43 | tm->tm_mday = dayno + 1; 44 | return tm; 45 | } 46 | 47 | blynk_time_t blynk_mk_gmtime(struct blynk_tm *tm) 48 | { 49 | long day, year; 50 | int tm_year; 51 | int yday, month; 52 | long seconds; 53 | int overflow; 54 | 55 | tm->tm_min += tm->tm_sec / 60; 56 | tm->tm_sec %= 60; 57 | if (tm->tm_sec < 0) { 58 | tm->tm_sec += 60; 59 | tm->tm_min--; 60 | } 61 | tm->tm_hour += tm->tm_min / 60; 62 | tm->tm_min = tm->tm_min % 60; 63 | if (tm->tm_min < 0) { 64 | tm->tm_min += 60; 65 | tm->tm_hour--; 66 | } 67 | day = tm->tm_hour / 24; 68 | tm->tm_hour = tm->tm_hour % 24; 69 | if (tm->tm_hour < 0) { 70 | tm->tm_hour += 24; 71 | day--; 72 | } 73 | tm->tm_year += tm->tm_mon / 12; 74 | tm->tm_mon %= 12; 75 | if (tm->tm_mon < 0) { 76 | tm->tm_mon += 12; 77 | tm->tm_year--; 78 | } 79 | day += (tm->tm_mday - 1); 80 | while (day < 0) { 81 | if (--tm->tm_mon < 0) { 82 | tm->tm_year--; 83 | tm->tm_mon = 11; 84 | } 85 | day += month_tab[IS_LEAP_YEAR(YEAR_0 + tm->tm_year)][tm->tm_mon]; 86 | } 87 | while (day >= month_tab[IS_LEAP_YEAR(YEAR_0 + tm->tm_year)][tm->tm_mon]) { 88 | day -= month_tab[IS_LEAP_YEAR(YEAR_0 + tm->tm_year)][tm->tm_mon]; 89 | if (++(tm->tm_mon) == 12) { 90 | tm->tm_mon = 0; 91 | tm->tm_year++; 92 | } 93 | } 94 | tm->tm_mday = day + 1; 95 | year = YEAR_EPOCH; 96 | if (tm->tm_year < year - YEAR_0) 97 | return (blynk_time_t) -1; 98 | seconds = 0; 99 | day = 0; 100 | overflow = 0; 101 | 102 | tm_year = tm->tm_year + YEAR_0; 103 | 104 | if (TIME_MAX / 365 < tm_year - year) 105 | overflow++; 106 | day = (tm_year - year) * 365; 107 | if (TIME_MAX - day < (tm_year - year) / 4 + 1) 108 | overflow++; 109 | day += (tm_year - year) / 4 + ((tm_year % 4) && tm_year % 4 < year % 4); 110 | day -= (tm_year - year) / 100 111 | + ((tm_year % 100) && tm_year % 100 < year % 100); 112 | day += (tm_year - year) / 400 113 | + ((tm_year % 400) && tm_year % 400 < year % 400); 114 | 115 | yday = month = 0; 116 | while (month < tm->tm_mon) { 117 | yday += month_tab[IS_LEAP_YEAR(tm_year)][month]; 118 | month++; 119 | } 120 | yday += (tm->tm_mday - 1); 121 | if (day + yday < 0) 122 | overflow++; 123 | day += yday; 124 | 125 | tm->tm_yday = yday; 126 | tm->tm_wday = (day + 4) % 7; 127 | 128 | seconds = ((tm->tm_hour * 60L) + tm->tm_min) * 60L + tm->tm_sec; 129 | 130 | if ((TIME_MAX - seconds) / SECS_IN_DAY < day) 131 | overflow++; 132 | seconds += day * SECS_IN_DAY; 133 | 134 | if (overflow) 135 | return (blynk_time_t) -1; 136 | 137 | if ((blynk_time_t) seconds != seconds) 138 | return (blynk_time_t) -1; 139 | return (blynk_time_t) seconds; 140 | } 141 | 142 | int blynk_compute_sun(int8_t month, int8_t day, double latitude, double longitude, bool rise) 143 | { 144 | float y, decl, eqt, ha, lon, lat; 145 | uint8_t a; 146 | int minutes; 147 | 148 | month -= 1; 149 | day -= 1; 150 | lat = latitude/57.295779513082322; 151 | lon = -longitude/57.295779513082322; 152 | 153 | //approximate hour; 154 | a = (rise) ? 18 : 6; 155 | 156 | // approximate day of year 157 | y = month * 30.4375 + day + a/24.0; // 0... 365 158 | 159 | // compute fractional year 160 | y *= 1.718771839885e-02; // 0... 1 161 | 162 | // compute equation of time... .43068174 163 | eqt = 229.18 * (0.000075+0.001868*cos(y) -0.032077*sin(y) -0.014615*cos(y*2) -0.040849*sin(y* 2) ); 164 | 165 | // compute solar declination... -0.398272 166 | decl = 0.006918-0.399912*cos(y)+0.070257*sin(y)-0.006758*cos(y*2)+0.000907*sin(y*2)-0.002697*cos(y*3)+0.00148*sin(y*3); 167 | 168 | //compute hour angle 169 | ha = ( cos(1.585340737228125) / (cos(lat)*cos(decl)) -tan(lat) * tan(decl) ); 170 | 171 | if (fabs(ha) > 1.0) { // we're in the (ant)arctic and there is no rise(or set) today! 172 | return -1; 173 | } 174 | 175 | ha = acos(ha); 176 | if(!rise) ha = -ha; 177 | 178 | // compute minutes from midnight 179 | minutes = 720+4*(lon-ha)*57.295779513082322-eqt; 180 | 181 | return minutes; 182 | } 183 | 184 | -------------------------------------------------------------------------------- /src/utility/BlynkTimer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SimpleTimer.cpp 3 | * 4 | * SimpleTimer - A timer library for Arduino. 5 | * Author: mromani@ottotecnica.com 6 | * Copyright (c) 2010 OTTOTECNICA Italy 7 | * 8 | * Callback function parameters added & compiler warnings 9 | * removed by Bill Knight 20March2017 10 | * 11 | * This library is free software; you can redistribute it 12 | * and/or modify it under the terms of the GNU Lesser 13 | * General Public License as published by the Free Software 14 | * Foundation; either version 2.1 of the License, or (at 15 | * your option) any later version. 16 | * 17 | * This library is distributed in the hope that it will 18 | * be useful, but WITHOUT ANY WARRANTY; without even the 19 | * implied warranty of MERCHANTABILITY or FITNESS FOR A 20 | * PARTICULAR PURPOSE. See the GNU Lesser General Public 21 | * License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser 24 | * General Public License along with this library; if not, 25 | * write to the Free Software Foundation, Inc., 26 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 27 | */ 28 | 29 | 30 | #include "Blynk/BlynkTimer.h" 31 | #include 32 | 33 | // Select time function: 34 | //static inline unsigned long elapsed() { return micros(); } 35 | static inline unsigned long elapsed() { return BlynkMillis(); } 36 | 37 | 38 | SimpleTimer::SimpleTimer() 39 | : numTimers (-1) 40 | { 41 | } 42 | 43 | void SimpleTimer::init() { 44 | unsigned long current_millis = elapsed(); 45 | 46 | for (int i = 0; i < MAX_TIMERS; i++) { 47 | timer[i] = timer_t(); 48 | timer[i].prev_millis = current_millis; 49 | } 50 | 51 | numTimers = 0; 52 | } 53 | 54 | 55 | void SimpleTimer::run() { 56 | int i; 57 | unsigned long current_millis; 58 | 59 | // get current time 60 | current_millis = elapsed(); 61 | 62 | for (i = 0; i < MAX_TIMERS; i++) { 63 | 64 | timer[i].toBeCalled = DEFCALL_DONTRUN; 65 | 66 | // jump over empty slots 67 | if (isValidTimer(i)) { 68 | 69 | // is it time to process this timer ? 70 | // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 71 | 72 | if ((current_millis - timer[i].prev_millis) >= timer[i].delay) { 73 | 74 | if (timer[i].delay) { 75 | unsigned long skipTimes = (current_millis - timer[i].prev_millis) / timer[i].delay; 76 | // update time 77 | timer[i].prev_millis += timer[i].delay * skipTimes; 78 | } else { 79 | timer[i].prev_millis = current_millis; 80 | } 81 | 82 | // check if the timer callback has to be executed 83 | if (timer[i].enabled) { 84 | 85 | // "run forever" timers must always be executed 86 | if (timer[i].maxNumRuns == RUN_FOREVER) { 87 | timer[i].toBeCalled = DEFCALL_RUNONLY; 88 | } 89 | // other timers get executed the specified number of times 90 | else if (timer[i].numRuns < timer[i].maxNumRuns) { 91 | timer[i].toBeCalled = DEFCALL_RUNONLY; 92 | timer[i].numRuns++; 93 | 94 | // after the last run, delete the timer 95 | if (timer[i].numRuns >= timer[i].maxNumRuns) { 96 | timer[i].toBeCalled = DEFCALL_RUNANDDEL; 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | 104 | for (i = 0; i < MAX_TIMERS; i++) { 105 | if (timer[i].toBeCalled == DEFCALL_DONTRUN) 106 | continue; 107 | 108 | if (timer[i].hasParam) 109 | timer[i].callback_p(timer[i].param); 110 | else 111 | timer[i].callback(); 112 | 113 | if (timer[i].toBeCalled == DEFCALL_RUNANDDEL) 114 | deleteTimer(i); 115 | } 116 | } 117 | 118 | 119 | // find the first available slot 120 | // return -1 if none found 121 | int SimpleTimer::findFirstFreeSlot() { 122 | // all slots are used 123 | if (numTimers >= MAX_TIMERS) { 124 | return -1; 125 | } 126 | 127 | // return the first slot with no callback (i.e. free) 128 | for (int i = 0; i < MAX_TIMERS; i++) { 129 | if (!isValidTimer(i)) { 130 | return i; 131 | } 132 | } 133 | 134 | // no free slots found 135 | return -1; 136 | } 137 | 138 | 139 | int SimpleTimer::setupTimer(unsigned long d, const timer_callback& f, unsigned n) { 140 | int freeTimer; 141 | 142 | if (numTimers < 0) { 143 | init(); 144 | } 145 | 146 | freeTimer = findFirstFreeSlot(); 147 | if (freeTimer < 0) { 148 | return -1; 149 | } 150 | 151 | if (f == NULL) { 152 | return -1; 153 | } 154 | 155 | timer[freeTimer].delay = d; 156 | timer[freeTimer].callback = f; 157 | timer[freeTimer].hasParam = false; 158 | timer[freeTimer].maxNumRuns = n; 159 | timer[freeTimer].enabled = true; 160 | timer[freeTimer].prev_millis = elapsed(); 161 | 162 | numTimers++; 163 | 164 | return freeTimer; 165 | } 166 | 167 | int SimpleTimer::setupTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) { 168 | int freeTimer; 169 | 170 | if (numTimers < 0) { 171 | init(); 172 | } 173 | 174 | freeTimer = findFirstFreeSlot(); 175 | if (freeTimer < 0) { 176 | return -1; 177 | } 178 | 179 | if (f == NULL) { 180 | return -1; 181 | } 182 | 183 | timer[freeTimer].delay = d; 184 | timer[freeTimer].callback_p = f; 185 | timer[freeTimer].param = p; 186 | timer[freeTimer].hasParam = true; 187 | timer[freeTimer].maxNumRuns = n; 188 | timer[freeTimer].enabled = true; 189 | timer[freeTimer].prev_millis = elapsed(); 190 | 191 | numTimers++; 192 | 193 | return freeTimer; 194 | } 195 | 196 | bool SimpleTimer::changeInterval(unsigned numTimer, unsigned long d) { 197 | if (numTimer >= MAX_TIMERS) { 198 | return false; 199 | } 200 | 201 | // Updates interval of existing specified timer 202 | if (isValidTimer(numTimer)) { 203 | timer[numTimer].delay = d; 204 | timer[numTimer].prev_millis = elapsed(); 205 | return true; 206 | } 207 | // false return for non-used numTimer, no callback 208 | return false; 209 | } 210 | 211 | void SimpleTimer::deleteTimer(unsigned timerId) { 212 | if (timerId >= MAX_TIMERS) { 213 | return; 214 | } 215 | 216 | // nothing to delete if no timers are in use 217 | if (numTimers == 0) { 218 | return; 219 | } 220 | 221 | // don't decrease the number of timers if the 222 | // specified slot is already empty 223 | if (isValidTimer(timerId)) { 224 | timer[timerId] = timer_t(); 225 | timer[timerId].prev_millis = elapsed(); 226 | 227 | // update number of timers 228 | numTimers--; 229 | } 230 | } 231 | 232 | 233 | // function contributed by code@rowansimms.com 234 | void SimpleTimer::restartTimer(unsigned numTimer) { 235 | if (numTimer >= MAX_TIMERS) { 236 | return; 237 | } 238 | 239 | timer[numTimer].prev_millis = elapsed(); 240 | } 241 | 242 | void SimpleTimer::executeNow(unsigned numTimer) { 243 | if (numTimer >= MAX_TIMERS) { 244 | return; 245 | } 246 | 247 | timer[numTimer].prev_millis = elapsed() - timer[numTimer].delay; 248 | } 249 | 250 | bool SimpleTimer::isEnabled(unsigned numTimer) { 251 | if (numTimer >= MAX_TIMERS) { 252 | return false; 253 | } 254 | 255 | return timer[numTimer].enabled; 256 | } 257 | 258 | 259 | void SimpleTimer::enable(unsigned numTimer) { 260 | if (numTimer >= MAX_TIMERS) { 261 | return; 262 | } 263 | 264 | timer[numTimer].enabled = true; 265 | } 266 | 267 | 268 | void SimpleTimer::disable(unsigned numTimer) { 269 | if (numTimer >= MAX_TIMERS) { 270 | return; 271 | } 272 | 273 | timer[numTimer].enabled = false; 274 | } 275 | 276 | void SimpleTimer::enableAll() { 277 | // Enable all timers with a callback assigned (used) 278 | for (int i = 0; i < MAX_TIMERS; i++) { 279 | if (isValidTimer(i) && timer[i].numRuns == RUN_FOREVER) { 280 | timer[i].enabled = true; 281 | } 282 | } 283 | } 284 | 285 | void SimpleTimer::disableAll() { 286 | // Disable all timers with a callback assigned (used) 287 | for (int i = 0; i < MAX_TIMERS; i++) { 288 | if (isValidTimer(i) && timer[i].numRuns == RUN_FOREVER) { 289 | timer[i].enabled = false; 290 | } 291 | } 292 | } 293 | 294 | void SimpleTimer::toggle(unsigned numTimer) { 295 | if (numTimer >= MAX_TIMERS) { 296 | return; 297 | } 298 | 299 | timer[numTimer].enabled = !timer[numTimer].enabled; 300 | } 301 | 302 | 303 | unsigned SimpleTimer::getNumTimers() { 304 | return numTimers; 305 | } 306 | -------------------------------------------------------------------------------- /src/utility/BlynkUtility.h: -------------------------------------------------------------------------------- 1 | 2 | #warning "Please include Blynk/BlynkUtility.h, instead of utility/BlynkUtility.h" 3 | #include 4 | -------------------------------------------------------------------------------- /verification.txt: -------------------------------------------------------------------------------- 1 | 2 | === VERIFICATION HOWTO === 3 | 4 | 1. Install the Blynk App on your Android/iOS smartphone 5 | 2. Login to Bynk App. If you don't have an account, please create one (specify a correct email) 6 | 3. Create a new project (you should get an email with Auth Token) 7 | 4. Follow this guide: http://docs.blynk.cc/#hardware-set-ups-particle 8 | --------------------------------------------------------------------------------