├── .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 | [](https://github.com/vshymanskyy/blynk-library-lua/releases/latest)
12 | [](https://github.com/vshymanskyy/blynk-library-lua/releases/latest)
13 | [](https://github.com/vshymanskyy/blynk-library-lua/stargazers)
14 | [](https://github.com/vshymanskyy/blynk-library-lua/issues)
15 | [](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 | [](https://github.com/blynkkk/blynk-library/stargazers)
19 | [](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 | 
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 |
--------------------------------------------------------------------------------