├── .gitignore ├── LICENSE ├── README.md ├── blynk.lua ├── blynk ├── nodemcu.lua ├── pipe.lua └── socket.lua ├── examples ├── client.lua └── nodemcu.lua └── timer.lua /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Volodymyr Shymanskyy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!IMPORTANT] 2 | > **This project is still available for exploration, but is no longer actively maintained or updated.** 3 | > We recommend switching to the Blynk MQTT API for a robust and future-proof experience. 4 | > Support for this project will be phased out over time. 5 | > You can explore some [useful MQTT examples here](https://github.com/Blynk-Technologies/Blynk-MQTT-Samples). 6 | 7 | # Lua client for Blynk IoT 8 | 9 | **Note:** The library has been updated for Blynk 2.0 10 | 11 | [![GitHub version](https://img.shields.io/github/release/vshymanskyy/blynk-library-lua.svg)](https://github.com/vshymanskyy/blynk-library-lua/releases/latest) 12 | [![GitHub download](https://img.shields.io/github/downloads/vshymanskyy/blynk-library-lua/total.svg)](https://github.com/vshymanskyy/blynk-library-lua/releases/latest) 13 | [![GitHub stars](https://img.shields.io/github/stars/vshymanskyy/blynk-library-lua.svg)](https://github.com/vshymanskyy/blynk-library-lua/stargazers) 14 | [![GitHub issues](https://img.shields.io/github/issues/vshymanskyy/blynk-library-lua.svg)](https://github.com/vshymanskyy/blynk-library-lua/issues) 15 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/vshymanskyy/blynk-library-lua/blob/master/LICENSE) 16 | 17 | If you like **Blynk** - give it a star, or fork it and contribute! 18 | [![GitHub stars](https://img.shields.io/github/stars/blynkkk/blynk-library.svg?style=social&label=Star)](https://github.com/blynkkk/blynk-library/stargazers) 19 | [![GitHub forks](https://img.shields.io/github/forks/blynkkk/blynk-library.svg?style=social&label=Fork)](https://github.com/blynkkk/blynk-library/network) 20 | __________ 21 | 22 | ## What is Blynk? 23 | Blynk provides **iOS** and **Android** apps to control any hardware **over the Internet** or **directly using Bluetooth**. 24 | You can easily build graphic interfaces for all your projects by simply dragging and dropping widgets, **right on your smartphone**. 25 | Blynk is **the most popular IoT platform** used by design studios, makers, educators, and equipment vendors all over the world. 26 | 27 | ![Blynk Banner](https://github.com/blynkkk/blynkkk.github.io/blob/master/images/GithubBanner.jpg) 28 | 29 | ## Download 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 | ## Documentation 36 | Social: [Webpage](http://www.blynk.cc) / [Facebook](http://www.fb.com/blynkapp) / [Twitter](http://twitter.com/blynk_app) / [Kickstarter](https://www.kickstarter.com/projects/167134865/blynk-build-an-app-for-your-arduino-project-in-5-m/description) 37 | Documentation: https://docs.blynk.io 38 | Community Forum: http://community.blynk.cc 39 | Blynk for Business: http://www.blynk.io 40 | 41 | ## Usage example 42 | 43 | ```lua 44 | local Blynk = require("blynk.socket") 45 | 46 | local blynk = Blynk.new("your_auth_token") 47 | 48 | -- callback to run when V1 changes 49 | blynk:on("V1", function(param) 50 | print("V1:", tonumber(param[1]), tonumber(param[2])) 51 | end) 52 | 53 | -- callback to run when cloud requests V2 value 54 | blynk:on("readV2", function(param) 55 | blynk:virtualWrite(2, os.time()) 56 | end) 57 | 58 | local sock = getSocketConnection() -- omitted 59 | blynk:connect(sock) 60 | 61 | while true do 62 | blynk:run() 63 | end 64 | ``` 65 | 66 | You can run the [full example](examples/client.lua): 67 | 68 | ```sh 69 | lua ./examples/client.lua 70 | ``` 71 | 72 | ## Features 73 | - **Lua 5.1, Lua 5.2, Lua 5.3, LuaJIT** support 74 | - ** Linux, 75 | Windows, 76 | MacOS** support 77 | - `virtualWrite` 78 | - `syncVirtual` 79 | - `setProperty` 80 | - `logEvent` 81 | - events: `Vn`, `readVn`, `connected`, `disconnected`, `redirect` 82 | - `TCP` and secure `TLS/SSL` connection support 83 | - can run on embedded hardware, like `NodeMCU` or `OpenWrt` 84 | 85 | ## OpenWrt installation 86 | 87 | ```sh 88 | opkg update 89 | opkg install lua luasocket luasec 90 | # openssl is needed for wget to handle https:// 91 | opkg install wget openssl-util libustream-wolfssl 92 | 93 | # Get blynk-library-lua from github 94 | cd /root 95 | wget --no-check-certificate -qO- https://github.com/vshymanskyy/blynk-library-lua/archive/v0.2.0.tar.gz | tar xvz 96 | cd blynk-library-lua-0.2.0 97 | 98 | # Run it 99 | lua ./examples/client.lua 100 | ``` 101 | 102 | ## NodeMCU installation 103 | 104 | It is very easy to get it running on NodeMCU (or any other `ESP8266`/`ESP32`-based device): 105 | - Get the latest [nodemcu-firmware](https://github.com/nodemcu/nodemcu-firmware) running on your device. 106 | You can use their [online build service](https://nodemcu-build.com/). 107 | It is recommended to include `encoder`, `TLS/SSL` modules. 108 | - Edit `nodemcu.lua` example (put your `auth token` and wifi credentials) 109 | - Use `nodemcu-tool` or any other method to transfer lua files to the device. 110 | **Note:** the NodeMCU filesystem is "flat" (folders not supported), but it handles the `/` symbol nicely. 111 | Be sure to preserve the relative path when copying files: 112 | ```sh 113 | nodemcu-tool upload -mck ./blynk.lua ./blynk/pipe.lua ./blynk/nodemcu.lua 114 | nodemcu-tool upload ./examples/nodemcu.lua -n init.lua 115 | ``` 116 | - Open device terminal and run `dofile("init.lua")` 117 | - `blynk` object is global, so you can call it from the interactive console: 118 | ```lua 119 | blynk:virtualWrite(1, tmr.time()) 120 | ``` 121 | 122 | ## Ubuntu/Linux/Raspberry Pi installation 123 | 124 | ```sh 125 | sudo apt-get install lua5.3 lua-sec lua-socket 126 | ``` 127 | 128 | ## Bonus 129 | 130 | The `Timer` is included for demonstration purposes. 131 | Here are also some handy functions: 132 | 133 | ```lua 134 | local function millis() 135 | return math.floor(socket.gettime()*1000) 136 | end 137 | 138 | local function delay(msec) 139 | return socket.sleep(msec/1000) 140 | end 141 | ``` 142 | __________ 143 | 144 | ### Implementations for other platforms 145 | * [Arduino](https://github.com/blynkkk/blynk-library) 146 | * [Particle](https://github.com/vshymanskyy/blynk-library-spark) 147 | * [Node.js, Espruino, Browsers](https://github.com/vshymanskyy/blynk-library-js) 148 | * [Python, MicroPython](https://github.com/vshymanskyy/blynk-library-python) 149 | * [OpenWrt packages](https://github.com/vshymanskyy/blynk-library-openwrt) 150 | * [MBED](https://developer.mbed.org/users/vshymanskyy/code/Blynk/) 151 | * [Node-RED for Blynk IoT](https://flows.nodered.org/node/node-red-contrib-blynk-iot) 152 | * [LabVIEW](https://github.com/juncaofish/NI-LabVIEWInterfaceforBlynk) 153 | * [C#](https://github.com/sverrefroy/BlynkLibrary) 154 | 155 | ### License 156 | This project is released under The MIT License (MIT) 157 | -------------------------------------------------------------------------------- /blynk.lua: -------------------------------------------------------------------------------- 1 | --[[ Copyright (c) 2018 Volodymyr Shymanskyy. See the file LICENSE for copying permission. ]] 2 | 3 | local Pipe = require("blynk.pipe") 4 | 5 | local COMMAND = { rsp = 0, login = 2, ping = 6, bridge = 15, hw_sync = 16, internal = 17, set_prop = 19, hw = 20, hw_login = 29, redirect = 41, debug = 55, event = 64 } 6 | local STATUS = { success = 200, invalid_token = 9 } 7 | local STATE_AUTH = "auth" 8 | local STATE_CONNECT = "connected" 9 | local STATE_DISCONNECT = "disconnected" 10 | 11 | local unpack = table.unpack or unpack 12 | 13 | local function split(str, delimiter) 14 | local result = { } 15 | local from = 1 16 | local delim_from, delim_to = string.find( str, delimiter, from ) 17 | while delim_from do 18 | table.insert( result, string.sub( str, from , delim_from-1 ) ) 19 | from = delim_to + 1 20 | delim_from, delim_to = string.find( str, delimiter, from ) 21 | end 22 | table.insert( result, string.sub( str, from ) ) 23 | return result 24 | end 25 | 26 | local Blynk = { 27 | heartbeat = 50, 28 | buffin = 1024, 29 | callbacks = {}, 30 | state = STATE_DISCONNECT, 31 | log = function(...) end, 32 | _gettime = function() return os.time() end, 33 | } 34 | Blynk._VERSION = "0.2.0" 35 | Blynk.__index = Blynk 36 | 37 | print([[ 38 | ___ __ __ 39 | / _ )/ /_ _____ / /__ 40 | / _ / / // / _ \/ '_/ 41 | /____/_/\_, /_//_/_/\_\ 42 | /___/ for Lua v]] .. Blynk._VERSION .. "\n") 43 | 44 | function Blynk.new(auth, o) 45 | assert(string.len(auth) == 32, "Wrong auth token format") --sanity check 46 | o = o or {} 47 | local self = setmetatable(o, Blynk) 48 | self.auth = auth 49 | self.bin = Pipe.new() 50 | return self 51 | end 52 | 53 | function Blynk:on(evt, fun) self.callbacks[evt] = fun; return self end 54 | function Blynk:emit(evt, ...) local fun = self.callbacks[evt]; if fun ~= nil then fun(...) end end 55 | 56 | function Blynk:virtualWrite(pin, ...) 57 | self:sendMsg(COMMAND.hw, nil, 'vw\0'..pin..'\0'..table.concat({...}, '\0')) 58 | end 59 | 60 | function Blynk:setProperty(pin, prop, ...) 61 | self:sendMsg(COMMAND.set_prop, nil, pin..'\0'..prop..'\0'..table.concat({...}, '\0')) 62 | end 63 | 64 | function Blynk:syncVirtual(...) 65 | self:sendMsg(COMMAND.hw_sync, nil, 'vr\0'..table.concat({...}, '\0')) 66 | end 67 | 68 | function Blynk:logEvent(evt, descr) 69 | self:sendMsg(COMMAND.event, nil, table.concat({evt, descr}, '\0')) 70 | end 71 | 72 | function Blynk:sendMsg(cmd, id, payload) 73 | if self.state ~= STATE_CONNECT and self.state ~= STATE_AUTH then return end 74 | payload = payload or '' 75 | if id == nil then 76 | id = self.msg_id 77 | self.msg_id = self.msg_id + 1 78 | if self.msg_id > 0xFFFF then 79 | self.msg_id = 1 80 | end 81 | end 82 | self.log('< '..cmd..'|'..table.concat(split(payload, "\0"), ',')) 83 | local len = string.len(payload) 84 | local msg = table.concat{ 85 | string.char(cmd%256), 86 | string.char(math.floor(id/256)), string.char(id%256), 87 | string.char(math.floor(len/256)), string.char(len%256) 88 | } .. payload 89 | self.lastSend = self._gettime() 90 | self._send(msg) 91 | end 92 | 93 | function Blynk:connect() 94 | self.msg_id = 1 95 | self.lastRecv, self.lastSend, self.lastPing = self._gettime(), 0, 0 96 | self.bin:clear() 97 | self.state = STATE_AUTH 98 | self:sendMsg(COMMAND.hw_login, nil, self.auth) 99 | end 100 | 101 | function Blynk:disconnect() 102 | self.state = STATE_DISCONNECT 103 | self:emit(STATE_DISCONNECT) 104 | end 105 | 106 | function Blynk:process(data) 107 | if not (self.state == STATE_CONNECT or self.state == STATE_AUTH) then return end 108 | local now = self._gettime() 109 | if now - self.lastRecv > self.heartbeat+(self.heartbeat/2) then 110 | return self:disconnect() 111 | end 112 | if now - self.lastPing > self.heartbeat/10 and 113 | (now - self.lastSend > self.heartbeat or 114 | now - self.lastRecv > self.heartbeat) 115 | then 116 | self:sendMsg(COMMAND.ping) 117 | self.lastPing = now 118 | end 119 | 120 | if data then self.bin:push(data) end 121 | 122 | while true do 123 | -- 124 | local s = self.bin:pull(5) 125 | if s == nil then return end 126 | 127 | local cmd, i, len = (string.byte(s,1)), 128 | (string.byte(s,2) * 256 + string.byte(s,3)), 129 | (string.byte(s,4) * 256 + string.byte(s,5)) 130 | 131 | if i == 0 then return self:disconnect() end --sanity check 132 | self.lastRecv = now 133 | if cmd == COMMAND.rsp then 134 | self.log('> '..cmd..'|'..len) 135 | if self.state == STATE_AUTH and i == 1 then --login command 136 | if len == STATUS.success then 137 | self.state = STATE_CONNECT 138 | local ping = now - self.lastSend 139 | local info = {'ver', self._VERSION, 'h-beat', self.heartbeat, 'buff-in', self.buffin, 'dev', 'lua' } 140 | self:sendMsg(COMMAND.internal, nil, table.concat(info, '\0')) 141 | self:emit(STATE_CONNECT, ping) 142 | elseif len == STATUS.invalid_token then 143 | print("Invalid auth token") 144 | self:disconnect() 145 | else self:disconnect() end 146 | end 147 | else 148 | -- 149 | if len >= self.buffin then --sanity check 150 | print("Cmd too big: "..len) 151 | return self:disconnect() 152 | end 153 | local payload = self.bin:pull(len) 154 | if payload == nil then return self.bin:back(s) end --put the header back 155 | local args = split(payload, "\0") 156 | self.log('> '..cmd..'|'..table.concat(args, ',')) 157 | if cmd == COMMAND.ping then 158 | self:sendMsg(COMMAND.rsp, i, STATUS.success) 159 | elseif cmd == COMMAND.hw or cmd == COMMAND.bridge then 160 | if args[1] == 'vw' then 161 | self:emit("V"..args[2], {unpack(args, 3)}) 162 | elseif args[1] == 'vr' then 163 | self:emit("readV"..args[2]) 164 | end 165 | elseif cmd == COMMAND.internal then 166 | self:emit("internal:"..args[1], {unpack(args, 2)}) 167 | elseif cmd == COMMAND.redirect then 168 | --TODO 169 | elseif cmd == COMMAND.debug then 170 | print("Server says: "..args[1]) 171 | else --sanity check 172 | print("Unexpected command: "..cmd) 173 | self:disconnect() 174 | end 175 | -- 176 | end 177 | -- 178 | end 179 | end 180 | 181 | return Blynk 182 | -------------------------------------------------------------------------------- /blynk/nodemcu.lua: -------------------------------------------------------------------------------- 1 | --[[ Copyright (c) 2018 Volodymyr Shymanskyy. See the file LICENSE for copying permission. ]] 2 | 3 | local Blynk = require("blynk") 4 | local Pipe = require("blynk.pipe") 5 | 6 | local BlynkImpl = setmetatable( {}, { __index = Blynk } ) 7 | 8 | function BlynkImpl.new(...) 9 | local self = Blynk.new(...) 10 | self._gettime = function() return tmr.now()/1000000 end 11 | return setmetatable(self, { __index = BlynkImpl }) 12 | end 13 | 14 | function BlynkImpl:connect(sock) 15 | local canSend = true 16 | local pipe = Pipe.new() 17 | 18 | self._send = function(data) 19 | if data then pipe:push(data) end 20 | if canSend then 21 | local d = pipe:pull() 22 | if d:len() > 0 then 23 | canSend = false 24 | sock:send(d) 25 | end 26 | end 27 | end 28 | 29 | sock:on("sent", function(s) canSend = true; self._send() end) 30 | sock:on("receive", function(s, data) self:process(data) end) 31 | sock:on("disconnection", function(s) self:disconnect() end) 32 | 33 | Blynk.connect(self) 34 | end 35 | 36 | function BlynkImpl:run() 37 | self:process() 38 | end 39 | 40 | return BlynkImpl 41 | -------------------------------------------------------------------------------- /blynk/pipe.lua: -------------------------------------------------------------------------------- 1 | --[[ Copyright (c) 2018 Volodymyr Shymanskyy. See the file LICENSE for copying permission. ]] 2 | 3 | local Pipe = { b = "" } 4 | Pipe.__index = Pipe 5 | 6 | function Pipe.new() return setmetatable({}, Pipe) end 7 | function Pipe:clear() self.b = "" end 8 | function Pipe:len() return self.b:len() end 9 | function Pipe:push(data) self.b = self.b .. data end 10 | function Pipe:back(data) self.b = data .. self.b end 11 | 12 | function Pipe:pull(len) 13 | local res 14 | if len == nil then 15 | res = self.b; self.b = "" 16 | elseif self.b:len() >= len then 17 | res = self.b:sub(1,len); self.b = self.b:sub(len+1) 18 | end 19 | return res 20 | end 21 | 22 | return Pipe 23 | -------------------------------------------------------------------------------- /blynk/socket.lua: -------------------------------------------------------------------------------- 1 | --[[ Copyright (c) 2018 Volodymyr Shymanskyy. See the file LICENSE for copying permission. ]] 2 | 3 | local Blynk = require("blynk") 4 | local socket = require("socket") 5 | 6 | local BlynkImpl = setmetatable( {}, { __index = Blynk } ) 7 | 8 | function BlynkImpl.new(...) 9 | local self = Blynk.new(...) 10 | self._gettime = socket.gettime 11 | return setmetatable(self, { __index = BlynkImpl }) 12 | end 13 | 14 | function BlynkImpl:connect(sock) 15 | self.sock = sock 16 | 17 | -- set timeout, so run() won't freeze while waiting for input 18 | sock:settimeout(0.01) 19 | 20 | self._send = function(data) 21 | res, status = sock:send(data) 22 | if status == 'closed' then self:disconnect() end 23 | end 24 | 25 | Blynk.connect(self) 26 | end 27 | 28 | function BlynkImpl:run() 29 | local data, status, part = self.sock:receive(self.buffin) 30 | self:process(data or part) 31 | if status == "closed" then self:disconnect() end 32 | end 33 | 34 | return BlynkImpl 35 | -------------------------------------------------------------------------------- /examples/client.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | --[[ 4 | This is the default example for Linux, Windows, OpenWrt 5 | ]] 6 | 7 | local socket = require("socket") 8 | local use_ssl, ssl = pcall(require, "ssl") 9 | 10 | local Blynk = require("blynk.socket") 11 | local Timer = require("timer") 12 | 13 | assert(#arg >= 1, "Please specify Auth Token") 14 | local auth = arg[1] 15 | 16 | local blynk = Blynk.new(auth, { 17 | heartbeat = 30, -- default h-beat is 50 18 | --log = print, 19 | }) 20 | 21 | local function connectBlynk() 22 | local host = "blynk.cloud" 23 | 24 | local sock = assert(socket.tcp()) 25 | sock:setoption("tcp-nodelay", true) 26 | 27 | if use_ssl then 28 | print("Connecting Blynk (secure)...") 29 | sock:connect(host, 443) 30 | local opts = { 31 | mode = "client", 32 | protocol = "tlsv1_2" 33 | } 34 | sock = assert(ssl.wrap(sock, opts)) 35 | assert(sock:dohandshake()) 36 | else 37 | print("Connecting Blynk...") 38 | sock:connect(host, 80) 39 | end 40 | 41 | -- tell Blynk to use this socket 42 | blynk:connect(sock) 43 | end 44 | 45 | blynk:on("connected", function(ping) 46 | print("Ready. Ping: "..math.floor(ping*1000).."ms") 47 | -- whenever we connect, request an update of V1 48 | blynk:syncVirtual(1) 49 | end) 50 | 51 | blynk:on("disconnected", function() 52 | print("Disconnected.") 53 | -- auto-reconnect after 5 seconds 54 | socket.sleep(5) 55 | connectBlynk() 56 | end) 57 | 58 | -- callback to run when V1 changes 59 | blynk:on("V1", function(param) 60 | print("V1:", tonumber(param[1]), tonumber(param[2])) 61 | end) 62 | 63 | -- callback to run when cloud requests V2 value 64 | blynk:on("readV2", function(param) 65 | blynk:virtualWrite(2, os.time()) 66 | end) 67 | 68 | -- create a timer to update widget property 69 | local tmr1 = Timer:new{interval = 5000, func = function() 70 | blynk:setProperty(2, "label", os.time()) 71 | end} 72 | 73 | connectBlynk() 74 | 75 | while true do 76 | blynk:run() 77 | tmr1:run() 78 | end 79 | -------------------------------------------------------------------------------- /examples/nodemcu.lua: -------------------------------------------------------------------------------- 1 | 2 | --[[ 3 | This is an example for NodeMCU (ESP8266) 4 | ]] 5 | 6 | local Blynk = require("blynk.nodemcu") 7 | 8 | local config = { 9 | auth = "YourAuthToken", 10 | ssid = "YourNetworkName", 11 | pwd = "YourPassword", 12 | } 13 | 14 | blynk = Blynk.new(config.auth, { 15 | heartbeat = 10, -- default h-beat is 30 16 | --log = print, 17 | }) 18 | 19 | local function connectBlynk() 20 | local host = "blynk.cloud" 21 | 22 | local sock, port 23 | --[[TODO: TLS didn't work for some reason, commented out 24 | if tls ~= nil then 25 | print("Connecting Blynk (secure)...") 26 | sock = tls.createConnection() 27 | port = 443 28 | else]] 29 | print("Connecting Blynk...") 30 | sock = net.createConnection(net.TCP) 31 | port = 80 32 | --end 33 | 34 | sock:on("connection", function(s) blynk:connect(s) end) 35 | sock:connect(port, host) 36 | end 37 | 38 | -- connect wifi 39 | print("Connecting WiFi...") 40 | wifi.setmode(wifi.STATION) 41 | wifi.sta.config(config) 42 | wifi.sta.connect(connectBlynk) 43 | 44 | blynk:on("connected", function(ping) 45 | print("Ready. Ping: "..math.floor(ping*1000).."ms") 46 | -- whenever we connect, request an update of V1 47 | blynk:syncVirtual(1) 48 | end) 49 | 50 | blynk:on("disconnected", function() 51 | print("Disconnected.") 52 | -- auto-reconnect 53 | connectBlynk() 54 | end) 55 | 56 | -- callback to run when V1 changes 57 | blynk:on("V1", function(param) 58 | print("V1:", tonumber(param[1]), tonumber(param[2])) 59 | end) 60 | 61 | -- Blynk housekeeping 62 | local periodic = tmr.create() 63 | periodic:alarm(1000, tmr.ALARM_AUTO, function() 64 | blynk:run() 65 | end) 66 | -------------------------------------------------------------------------------- /timer.lua: -------------------------------------------------------------------------------- 1 | local socket = require("socket") 2 | 3 | local function millis() 4 | return math.floor(socket.gettime()*1000) 5 | end 6 | 7 | Timer = { 8 | lastRun = 0, 9 | } 10 | 11 | function Timer:new(o) 12 | o = o or {} 13 | setmetatable(o, self) 14 | self.__index = self 15 | return o 16 | end 17 | 18 | function Timer:run() 19 | local t = millis() 20 | if t - self.lastRun > self.interval then 21 | self.lastRun = t 22 | self.func() 23 | end 24 | end 25 | 26 | return Timer 27 | --------------------------------------------------------------------------------