├── LICENSE.txt
├── README.md
├── TIMERS.md
├── blynklib.py
├── blynklib_mp.py
├── blynktimer.py
├── certificate
└── blynk-cloud.com.crt
├── examples
├── 01_write_virtual_pin.py
├── 02_read_virtual_pin.py
├── 03_connect_disconnect.py
├── 04_email.py
├── 05_set_property_notify.py
├── 06_terminal_widget.py
├── 07_tweet_and_logging.py
├── 08_blynk_timer.py
├── 09_sync_virtual_pin.py
├── 10_rtc_sync.py
├── 11_ssl_socket.py
├── 12_app_connect_disconnect.py
├── esp32
│ ├── 01_touch_button.py
│ ├── 02_terminal_cli.py
│ ├── 03_temperature_humidity_dht22.py
│ └── README.md
├── esp8266
│ ├── 01_potentiometer.py
│ └── README.md
└── raspberry
│ ├── 01_weather_station_pi3b.py
│ └── README.md
├── setup.cfg
├── setup.py
└── test
├── test_blynk_connection.py
├── test_blynk_main.py
└── test_blynk_protocol.py
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-2020 Anton Morozenko
4 | Copyright (c) 2015-2019 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.
--------------------------------------------------------------------------------
/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 | # Blynk Python Library
8 | This library provides API to connect IoT hardware that supports Micropython/Python to Blynk Cloud and communiate with Blynk apps (iOS and Android). You can send raw and processed sensor data and remotely control anything that is connected to your hardware (relays, motors, servos) from anywhere in the world.
9 |
10 | [][lib-release]
11 | [][lib-release]
12 | [][lib-stars]
13 | [][lib-issues]
14 | [][lib-travis]
15 | [][lib-licence]
16 |
17 | If you like **Blynk** - give it a star, or fork it and contribute!
18 | [][lib-stars]
19 | [][lib-network]
20 |
21 |
22 | ![Blynk Banner][blynk-banner]
23 | ### Blynk is **the most popular Internet of Things platform** for connecting hardware to the cloud, designing apps to control them, and managing your deployed devices at scale.
24 |
25 | - 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.
26 | Full list of supported hardware can be found [here][blynk-hw].
27 |
28 | - With Blynk apps for **iOS** and **Android** apps you can easily build graphic interfaces for all of your projects by simply dragging and dropping widgets on your smartphone. It's a purely WYSIWG experience: no coding on iOS or Android required.
29 |
30 | - Hardware can connect to Blynk Cloud (open-source server) over the Internet using hardware connectivity on board, or with the use of various shields (Ethernet, WiFi, GSM, LTE, etc). Blynk Cloud is available for every user of Blynk **for free**.
31 |
32 |
33 |
34 |
35 | ## Installation of Blynk Python Library
36 |
37 | #### Installation via python pip
38 | - Check python availability in your system.
39 | ```commandline
40 | python --version
41 | ```
42 | To exclude compatibility issue preferable versions are Python 2.7.9 (or greater) or Python 3.4 (or greater)
43 | If python not present you can download and install it from [here][python-org].
44 |
45 | **NOTE:** To run python in "sandbox" you can try **virtualenv** module. Check [this document][virtual-env] how to do it.
46 |
47 | - If you’re using preferable versions of python mentioned above, then **pip** comes installed with Python by default.
48 | Check pip availability:
49 | ```commandline
50 | pip --version
51 | ```
52 | - Install blynk library
53 | ```commandline
54 | sudo pip install blynklib
55 | ```
56 |
57 | #### Manual installation
58 | Library can be installed locally from git sources:
59 |
60 | ```commandline
61 | git clone https://github.com/blynkkk/lib-python.git
62 | cd lib-python
63 | pip install --user -e .
64 |
65 | # sudo pip install -e . # if installation needed not for current but for all users
66 | ```
67 |
68 | #### Testing
69 | You can run unit tests for cPython version of library (blynklib.py) using the command:
70 |
71 | python setup.py test
72 |
73 | **NOTE** Blynklib version <0.2.6 should use pytest-mock<1.11.2. In version 1.11.2 were added restrictions for context manager usage
74 |
75 | **NOTE:** Unit tests for Micropython ENV are not available yet.
76 |
77 | #### Micropython installation
78 | Some hardware platforms can use **[Micropython][micropython-org]** package.
79 | This is helpful for preliminary testing and debugging of your code outside of real hardware. Supported platforms
80 | and related installation docs can be found [here][micropython-pkg].
81 |
82 |
83 | ## Features
84 | This library supports Python2, Python3 (blynklib.py) , and Micropython (blynklib_mp.py).
85 |
86 | - Communication with public or local [Blynk Server][blynk-server].
87 | - Exchange any data between your hardware and app
88 | - Tested to work with: Raspberry Pi (any), ESP32, ESP8266
89 |
90 | ##### List of available operations:
91 | - Subscribe to connect/disconnect events (ssl connection supported only by cPython lib)
92 | - Subscribe to read/write events of [virtual pins][blynk-vpins]
93 | - [Virtual Pin][blynk-vpins] write
94 | - [Virtual Pin][blynk-vpins] sync
95 | - Send mobile app push notifications
96 | - Send email notifications
97 | - Send twitter notifications
98 | - Change widget GUI parameters in Blynk app based on hardware input
99 |
100 |
101 | ## Quickstart
102 | 1. Install Blynk python library as described above
103 | 2. Install Blynk App:
104 | [
Google Play][blynk-app-android] |
105 | [
App Store][blynk-app-ios]
106 |
107 | - Create new account in Blynk app using your email address
108 | - Create a new Project in Blynk app
109 | - You will get Auth Token delivered to your email account.
110 | - Put this Auth Token within your python script to authenticate your device on [public][blynk-server-public] or [local][blynk-server]
111 |
112 | ```python
113 | BLYNK_AUTH = '' #insert your Auth Token here
114 | ```
115 |
116 | #### Usage example
117 | ```python
118 | import blynklib
119 | # import blynklib_mp as blynklib # micropython import
120 |
121 | BLYNK_AUTH = '' #insert your Auth Token here
122 | # base lib init
123 | blynk = blynklib.Blynk(BLYNK_AUTH)
124 |
125 | # advanced options of lib init
126 | # from __future__ import print_function
127 | # blynk = blynklib.Blynk(BLYNK_AUTH, server='blynk-cloud.com', port=80, ssl_cert=None,
128 | # heartbeat=10, rcv_buffer=1024, log=print)
129 |
130 | # Lib init with SSL socket connection
131 | # blynk = blynklib.Blynk(BLYNK_AUTH, port=443, ssl_cert='')
132 | # current blynk-cloud.com certificate stored in project as
133 | # https://github.com/blynkkk/lib-python/blob/master/certificate/blynk-cloud.com.crt
134 | # Note! ssl feature supported only by cPython
135 |
136 | # register handler for Virtual Pin V22 reading by Blynk App.
137 | # when a widget in Blynk App asks Virtual Pin data from server within given configurable interval (1,2,5,10 sec etc)
138 | # server automatically sends notification about read virtual pin event to hardware
139 | # this notification captured by current handler
140 | @blynk.handle_event('read V22')
141 | def read_virtual_pin_handler(pin):
142 |
143 | # your code goes here
144 | # ...
145 | # Example: get sensor value, perform calculations, etc
146 | sensor_data = ''
147 | critilcal_data_value = ''
148 |
149 | # send value to Virtual Pin and store it in Blynk Cloud
150 | blynk.virtual_write(pin, sensor_data)
151 |
152 | # you can define if needed any other pin
153 | # example: blynk.virtual_write(24, sensor_data)
154 |
155 | # you can perform actions if value reaches a threshold (e.g. some critical value)
156 | if sensor_data >= critilcal_data_value
157 |
158 | blynk.set_property(pin, 'color', '#FF0000') # set red color for the widget UI element
159 | blynk.notify('Warning critical value') # send push notification to Blynk App
160 | blynk.email(, 'Email Subject', 'Email Body') # send email to specified address
161 |
162 | # main loop that starts program and handles registered events
163 | while True:
164 | blynk.run()
165 | ```
166 | ## Other Examples
167 |
168 | Examples can be found **[here][blynk-py-examples]** Check them all to get familiar with main Blynk API features.
169 |
170 | ##### Core operations:
171 | - [01_write_virtual_pin.py](https://github.com/blynkkk/lib-python/blob/master/examples/01_write_virtual_pin.py): How to read incoming data from Blynk app to Virtual Pin and use it in your code
172 | - [02_read_virtual_pin.py](https://github.com/blynkkk/lib-python/blob/master/examples/02_read_virtual_pin.py): How to update value on Virtual Pin
173 | - [03_connect_disconnect.py](https://github.com/blynkkk/lib-python/blob/master/examples/03_connect_disconnect.py): Managing connection with Blynk Cloud
174 | - [04_email.py](https://github.com/blynkkk/lib-python/blob/master/examples/04_email.py): How to send send email and push notifications from your hardware
175 | - [05_set_property_notify.py](https://github.com/blynkkk/lib-python/blob/master/examples/05_set_property_notify.py): How to change some of widget UI properties like colors, labels, etc
176 | - [06_terminal_widget.py](https://github.com/blynkkk/lib-python/blob/master/examples/06_terminal_widget.py): Communication between hardware and app through Terminal widget)
177 | - [07_tweet_and_logging.py](https://github.com/blynkkk/lib-python/blob/master/examples/07_tweet_and_logging.py): How to post to Twitter and log events from your hardware
178 | - [08_blynk_timer.py](https://github.com/blynkkk/lib-python/blob/master/examples/08_blynk_timer.py): How send data periodically from hardware by using **[Blynk Timer][blynktimer-doc]**
179 | - [09_sync_virtual_pin.py](https://github.com/blynkkk/lib-python/blob/master/examples/09_sync_virtual_pin.py): How to sync virtual pin states and properties
180 | - [10_rtc_sync.py](https://github.com/blynkkk/lib-python/blob/master/examples/10_rtc_sync.py): How to perform RTC sync with blynk server
181 | - [11_ssl_socket.py](https://github.com/blynkkk/lib-python/blob/master/examples/11_ssl_socket.py): SSL server connection. Feature supported only by cPython library.
182 | - [12_app_connect_disconnect.py](https://github.com/blynkkk/lib-python/blob/master/examples/12_app_connect_disconnect.py): Managing APP connect/disconnect events with Blynk Cloud.
183 |
184 |
185 | ##### Raspberry Pi (any):
186 | Read [Raspberry Pi guide](https://github.com/blynkkk/lib-python/tree/master/examples/raspberry) first.
187 |
188 | - [01_weather_station_pi3b.py](https://github.com/blynkkk/lib-python/blob/master/examples/raspberry/01_weather_station_pi3b.py) Connect DHT22; BMP180 sensors and send data to Blynk app
189 |
190 | ##### ESP32
191 | Read [ESP32 guide](https://github.com/blynkkk/lib-python/tree/master/examples/esp32) first.
192 | - [01_touch_button.py](https://github.com/blynkkk/lib-python/blob/master/examples/esp32/01_touch_button.py) Connect TTP223B touch sensor to ESP32 and react to touch
193 | - [02_terminal_cli.py](https://github.com/blynkkk/lib-python/blob/master/examples/esp32/02_terminal_cli.py) Communication between ESP32 hardware and app through Terminal widget
194 | - [03_temperature_humidity_dht22.py](https://github.com/blynkkk/lib-python/blob/master/examples/esp32/03_temperature_humidity_dht22.py) Connect DHT22 sensor to ESP32 and send data to Blynk app
195 |
196 | ##### ESP8266
197 | Read [ESP8266 guide](https://github.com/blynkkk/lib-python/tree/master/examples/esp8266) first.
198 | - [01_potentiometer.py](https://github.com/blynkkk/lib-python/blob/master/examples/esp8266/01_potentiometer.py) Cconnect potentiometer to ESP8266 and send resistance value to the app
199 |
200 |
201 |
202 | ### Memory size limitations
203 | For hardware with limited memory size (ex. ESP8266) you can use ***frozen modules*** or ***frozen bytecode*** approaches
204 | to load **blynklib** or any other library to hardware.
205 |
206 | Read [this document][esp8266-readme] to get more information.
207 |
208 | ## Documentation and other helpful links
209 |
210 | [Full Blynk Documentation](https://docs.blynk.io) - a complete guide on Blynk features
211 |
212 | [Community (Forum)](https://community.blynk.cc) - join a 1'000'000 Blynk community to ask questions and share ideas
213 |
214 | [Official Website](https://blynk.io)
215 |
216 | **Social Media:**
217 |
218 | [Facebook](https://www.fb.com/blynkapp) [Twitter](https://twitter.com/blynk_app) [Youtube](https://www.youtube.com/blynk)
219 |
220 | [Instagram](https://www.instagram.com/blynk.iot/) [LinkedIn](https://www.linkedin.com/company/b-l-y-n-k/)
221 |
222 |
223 | ## Blynk libraries for other platforms
224 | * [C++](https://github.com/blynkkk/blynk-library)
225 | * [Node.js, Espruino, Browsers](https://github.com/vshymanskyy/blynk-library-js)
226 | * [Python](https://github.com/vshymanskyy/blynk-library-python) (by Volodymyr Shymanskyy)
227 | * [Particle](https://github.com/vshymanskyy/blynk-library-spark)
228 | * [Lua, OpenWrt, NodeMCU](https://github.com/vshymanskyy/blynk-library-lua)
229 | * [OpenWrt packages](https://github.com/vshymanskyy/blynk-library-openwrt)
230 | * [MBED](https://developer.mbed.org/users/vshymanskyy/code/Blynk/)
231 | * [Node-RED for Blynk IoT](https://flows.nodered.org/node/node-red-contrib-blynk-iot)
232 | * [LabVIEW](https://github.com/juncaofish/NI-LabVIEWInterfaceforBlynk)
233 | * [C#](https://github.com/sverrefroy/BlynkLibrary)
234 |
235 | ## Contributing
236 | You are very welcome to contribute: stability bugfixes, new hardware support, or any other improvements. Please.
237 |
238 |
239 | ### License
240 | This project is released under The MIT License (MIT)
241 |
242 |
243 | [lib-release]: https://github.com/blynkkk/lib-python/releases/latest
244 | [lib-licence]: https://github.com/blynkkk/lib-python/blob/master/LICENSE
245 | [lib-travis]: https://travis-ci.org/blynkkk/lib-python
246 | [lib-issues]: https://github.com/blynkkk/lib-python/issues
247 | [lib-stars]: https://github.com/blynkkk/lib-python/stargazers
248 | [lib-network]: https://github.com/blynkkk/lib-python/network
249 | [blynk-io]: https://github.com/blynkkk/blynkkk.github.io
250 | [blynk-hw]: https://github.com/blynkkk/blynkkk.github.io/blob/master/SupportedHardware.md
251 | [blynk-architecture]: https://github.com/blynkkk/blynkkk.github.io/blob/master/images/architecture.png
252 | [blynk-banner]: https://github.com/blynkkk/blynkkk.github.io/blob/master/images/GithubBanner.jpg
253 | [blynk-server]: https://github.com/blynkkk/blynk-server
254 | [blynk-server-public]: http://blynk-cloud.com
255 | [blynk-docs]: https://docs.blynk.cc/
256 | [blynk-py-examples]: https://github.com/blynkkk/lib-python/blob/master/examples
257 | [blynk-app-android]: https://play.google.com/store/apps/details?id=cloud.blynk
258 | [blynk-app-ios]: https://apps.apple.com/us/app/blynk-iot/id1559317868
259 | [blynk-vpins]: http://help.blynk.cc/getting-started-library-auth-token-code-examples/blynk-basics/what-is-virtual-pins
260 | [python-org]: https://www.python.org/downloads/
261 | [micropython-org]: https://micropython.org/
262 | [micropython-pkg]: https://github.com/micropython/micropython/wiki/Getting-Started
263 | [virtual-env]: https://virtualenv.pypa.io/en/latest/installation/
264 | [esp8266-readme]: https://github.com/blynkkk/lib-python/blob/master/examples/esp8266/README.md
265 | [blynktimer-doc]: https://github.com/blynkkk/lib-python/blob/master/TIMERS.md
266 |
--------------------------------------------------------------------------------
/TIMERS.md:
--------------------------------------------------------------------------------
1 | # Blynk Timers
2 | There are two options of setting polling timers in **blynk**
3 |
4 | - create timers for your functions on hardware side
5 | - create timers on Blynk App side.
6 |
7 | ### Hardware timers
8 | Existing core library solutions may be helpful for hardware timers creation.
9 |
10 | For example:
11 | - micropython provides [machine.Timer][micropython-timer]
12 | - for cPython [threading.Timer][threading-timer] can be used
13 | - etc
14 |
15 | Unfortunately mentioned above solutions may be not so lightweight and clear as expected.
16 | For Quickstart we provide separate [timer module][blynktimer] that allows execute functions periodically or run them once.
17 |
18 | ##### Basic usage examples
19 | ```python
20 | from blynktimer import Timer
21 | blynk_timer = Timer()
22 |
23 | # run once timer that will fire after 1 sec
24 | @blynk_timer.register(interval=1, run_once=True)
25 | def your_run_once_function():
26 | print('Hello, World!')
27 |
28 | # periodical timer that will fire each 5 sec
29 | # run_once flag by default is False
30 | @blynk_timer.register(interval=5)
31 | def your_periodical_function():
32 | print('Hello, Blynkers!')
33 |
34 | while True:
35 | blynk_timer.run()
36 |
37 | ```
38 |
39 | ##### Advanced usage examples
40 | ```python
41 | import time
42 | from blynktimer import Timer
43 |
44 | # disable exception raise if all all timers were stopped
45 | blynk_timer = Timer(no_timers_err=False)
46 |
47 |
48 | # register two timers for single function with different function parameters
49 | @blynk_timer.register('p1', 'p2', c=1, interval=2, run_once=True)
50 | @blynk_timer.register('fp1', 'fp2', interval=3, run_once=False)
51 | def function1(a, b, c=2):
52 | time.sleep(c)
53 | print('Function params: {} {} {}'.format(a, b, c))
54 |
55 |
56 | # simple function registration for further stop
57 | # interval default = 10 sec
58 | # run_once default is False
59 | @blynk_timer.register()
60 | def function2():
61 | print('Function2')
62 |
63 |
64 | # list available timers
65 | print(blynk_timer.get_timers())
66 |
67 | # switch timer state to stopped by timer id
68 | # id = order_num + '_' + function_name
69 | # OR: on ports with low memory (such as the esp8266)
70 | # id = order_num + '_' + 'timer'
71 | blynk_timer.stop('2_function2')
72 |
73 |
74 | while True:
75 | intervals = blynk_timer.run()
76 | # print real passed time for timer fired events
77 | # maybe needed for debug
78 | if any(intervals):
79 | print(intervals)
80 | ```
81 |
82 | To get more accuracy for timers intervals it is possible to decrease library WAIT_SEC parameter. Default value = 0.05 sec
83 |
84 | ### Blynk App timers
85 | Some Blynk app widgets have timer setting where yoy can define (1,2,5,10 etc) seconds intervals for reading
86 | virtual pin values.
87 |
88 | Flow:
89 | - each N seconds Blynk app widget will do Virtual Pin reading operation.
90 | - Blynk Server for App read request will return current pin value
91 | - Additionally Blynk server will fire read virtual pin event and send it to hardware
92 | - If read pin event was registered on hardware certain handler will be executed
93 |
94 | [micropython-timer]: https://docs.micropython.org/en/latest/library/machine.Timer.html
95 | [threading-timer]:https://docs.python.org/3/library/threading.html#threading.Timer
96 | [blynktimer]: https://github.com/blynkkk/lib-python/blob/master/blynktimer.py
--------------------------------------------------------------------------------
/blynklib.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2019-2020 Anton Morozenko
2 | # Copyright (c) 2015-2019 Volodymyr Shymanskyy.
3 | # See the file LICENSE for copying permission.
4 |
5 | __version__ = '0.2.6'
6 |
7 | import socket
8 | import ssl
9 | import struct
10 | import time
11 |
12 | LOGO = """
13 | ___ __ __
14 | / _ )/ /_ _____ / /__
15 | / _ / / // / _ \\/ '_/
16 | /____/_/\\_, /_//_/_/\\_\\
17 | /___/ for Python v{}\n""".format(__version__)
18 |
19 |
20 | def stub_log(*args):
21 | pass
22 |
23 |
24 | def ticks_ms():
25 | return int(time.time() * 1000)
26 |
27 |
28 | def sleep_ms(ms):
29 | time.sleep(ms // 1000)
30 |
31 |
32 | class BlynkError(Exception):
33 | pass
34 |
35 |
36 | class RedirectError(Exception):
37 | def __init__(self, server, port):
38 | self.server = server
39 | self.port = port
40 |
41 |
42 | class Protocol(object):
43 | MSG_RSP = 0
44 | MSG_LOGIN = 2
45 | MSG_PING = 6
46 | MSG_TWEET = 12
47 | MSG_EMAIL = 13
48 | MSG_NOTIFY = 14
49 | MSG_BRIDGE = 15
50 | MSG_HW_SYNC = 16
51 | MSG_INTERNAL = 17
52 | MSG_PROPERTY = 19
53 | MSG_HW = 20
54 | MSG_REDIRECT = 41
55 | MSG_HEAD_LEN = 5
56 |
57 | STATUS_INVALID_TOKEN = 9
58 | STATUS_NO_DATA = 17
59 | STATUS_OK = 200
60 | VPIN_MAX_NUM = 32
61 |
62 | _msg_id = 0
63 |
64 | def _get_msg_id(self, **kwargs):
65 | if 'msg_id' in kwargs:
66 | return kwargs['msg_id']
67 | self._msg_id += 1
68 | return self._msg_id if self._msg_id <= 0xFFFF else 1
69 |
70 | def _pack_msg(self, msg_type, *args, **kwargs):
71 | data = ('\0'.join([str(curr_arg) for curr_arg in args])).encode('utf-8')
72 | return struct.pack('!BHH', msg_type, self._get_msg_id(**kwargs), len(data)) + data
73 |
74 | def parse_response(self, rsp_data, msg_buffer):
75 | msg_args = []
76 | try:
77 | msg_type, msg_id, h_data = struct.unpack('!BHH', rsp_data[:self.MSG_HEAD_LEN])
78 | except Exception as p_err:
79 | raise BlynkError('Message parse error: {}'.format(p_err))
80 | if msg_id == 0:
81 | raise BlynkError('invalid msg_id == 0')
82 | elif h_data >= msg_buffer:
83 | raise BlynkError('Command too long. Length = {}'.format(h_data))
84 | elif msg_type in (self.MSG_RSP, self.MSG_PING):
85 | pass
86 | elif msg_type in (self.MSG_HW, self.MSG_BRIDGE, self.MSG_INTERNAL, self.MSG_REDIRECT):
87 | msg_body = rsp_data[self.MSG_HEAD_LEN: self.MSG_HEAD_LEN + h_data]
88 | msg_args = [itm.decode('utf-8') for itm in msg_body.split(b'\0')]
89 | else:
90 | raise BlynkError("Unknown message type: '{}'".format(msg_type))
91 | return msg_type, msg_id, h_data, msg_args
92 |
93 | def heartbeat_msg(self, heartbeat, rcv_buffer):
94 | return self._pack_msg(self.MSG_INTERNAL, 'ver', __version__, 'buff-in', rcv_buffer, 'h-beat', heartbeat,
95 | 'dev', 'python')
96 |
97 | def login_msg(self, token):
98 | return self._pack_msg(self.MSG_LOGIN, token)
99 |
100 | def ping_msg(self):
101 | return self._pack_msg(self.MSG_PING)
102 |
103 | def response_msg(self, *args, **kwargs):
104 | return self._pack_msg(self.MSG_RSP, *args, **kwargs)
105 |
106 | def virtual_write_msg(self, v_pin, *val):
107 | return self._pack_msg(self.MSG_HW, 'vw', v_pin, *val)
108 |
109 | def virtual_sync_msg(self, *pins):
110 | return self._pack_msg(self.MSG_HW_SYNC, 'vr', *pins)
111 |
112 | def email_msg(self, to, subject, body):
113 | return self._pack_msg(self.MSG_EMAIL, to, subject, body)
114 |
115 | def tweet_msg(self, msg):
116 | return self._pack_msg(self.MSG_TWEET, msg)
117 |
118 | def notify_msg(self, msg):
119 | return self._pack_msg(self.MSG_NOTIFY, msg)
120 |
121 | def set_property_msg(self, pin, prop, *val):
122 | return self._pack_msg(self.MSG_PROPERTY, pin, prop, *val)
123 |
124 | def internal_msg(self, *args):
125 | return self._pack_msg(self.MSG_INTERNAL, *args)
126 |
127 |
128 | class Connection(Protocol):
129 | SOCK_MAX_TIMEOUT = 5
130 | SOCK_TIMEOUT = 0.05
131 | SOCK_SSL_TIMEOUT = 1
132 | EAGAIN = 11
133 | ETIMEDOUT = 60
134 | RETRIES_TX_DELAY = 2
135 | RETRIES_TX_MAX_NUM = 3
136 | RECONNECT_SLEEP = 1
137 | TASK_PERIOD_RES = 50
138 | DISCONNECTED = 0
139 | CONNECTING = 1
140 | AUTHENTICATING = 2
141 | AUTHENTICATED = 3
142 |
143 | _state = None
144 | _socket = None
145 | _last_rcv_time = 0
146 | _last_ping_time = 0
147 | _last_send_time = 0
148 |
149 | def __init__(self, token, server='blynk-cloud.com', port=80, ssl_cert=None, heartbeat=10, rcv_buffer=1024,
150 | log=stub_log):
151 | self.token = token
152 | self.server = server
153 | self.port = port
154 | self.heartbeat = heartbeat
155 | self.rcv_buffer = rcv_buffer
156 | self.log = log
157 | self.ssl_cert = ssl_cert
158 |
159 | def send(self, data):
160 | retries = self.RETRIES_TX_MAX_NUM
161 | while retries > 0:
162 | try:
163 | retries -= 1
164 | self._last_send_time = ticks_ms()
165 | return self._socket.send(data)
166 | except (IOError, OSError):
167 | sleep_ms(self.RETRIES_TX_DELAY)
168 |
169 | def receive(self, length, timeout):
170 | d_buff = b''
171 | try:
172 | self._socket.settimeout(timeout)
173 | d_buff += self._socket.recv(length)
174 | if len(d_buff) >= length:
175 | d_buff = d_buff[:length]
176 | return d_buff
177 | except (IOError, OSError) as err:
178 | if 'timed out' in str(err):
179 | return b''
180 | if str(self.EAGAIN) in str(err) or str(self.ETIMEDOUT) in str(err):
181 | return b''
182 | raise
183 |
184 | def is_server_alive(self):
185 | now = ticks_ms()
186 | h_beat_ms = self.heartbeat * 1000
187 | rcv_delta = now - self._last_rcv_time
188 | ping_delta = now - self._last_ping_time
189 | send_delta = now - self._last_send_time
190 | if rcv_delta > h_beat_ms + (h_beat_ms // 2):
191 | return False
192 | if (ping_delta > h_beat_ms // 10) and (send_delta > h_beat_ms or rcv_delta > h_beat_ms):
193 | self.send(self.ping_msg())
194 | self.log('Heartbeat time: {}'.format(now))
195 | self._last_ping_time = now
196 | return True
197 |
198 | def _get_socket(self):
199 | try:
200 | self._state = self.CONNECTING
201 | self._socket = socket.socket()
202 | self._socket.connect(socket.getaddrinfo(self.server, self.port)[0][4])
203 | self._socket.settimeout(self.SOCK_TIMEOUT)
204 | if self.ssl_cert:
205 | # system default CA certificates case
206 | if self.ssl_cert == "default":
207 | self.ssl_cert = None
208 | self.log('Using SSL socket...')
209 | ssl_context = ssl.create_default_context(cafile=self.ssl_cert)
210 | ssl_context.verify_mode = ssl.CERT_REQUIRED
211 | self._socket.settimeout(self.SOCK_SSL_TIMEOUT)
212 | self._socket = ssl_context.wrap_socket(sock=self._socket, server_hostname=self.server)
213 | self.log('Connected to blynk server')
214 | except Exception as g_exc:
215 | raise BlynkError('Connection with the Blynk server failed: {}'.format(g_exc))
216 |
217 | def _authenticate(self):
218 | self.log('Authenticating device...')
219 | self._state = self.AUTHENTICATING
220 | self.send(self.login_msg(self.token))
221 | rsp_data = self.receive(self.rcv_buffer, self.SOCK_MAX_TIMEOUT)
222 | if not rsp_data:
223 | raise BlynkError('Auth stage timeout')
224 | msg_type, _, status, args = self.parse_response(rsp_data, self.rcv_buffer)
225 | if status != self.STATUS_OK:
226 | if status == self.STATUS_INVALID_TOKEN:
227 | raise BlynkError('Invalid Auth Token')
228 | if msg_type == self.MSG_REDIRECT:
229 | raise RedirectError(*args)
230 | raise BlynkError('Auth stage failed. Status={}'.format(status))
231 | self._state = self.AUTHENTICATED
232 | self.log('Access granted')
233 |
234 | def _set_heartbeat(self):
235 | self.send(self.heartbeat_msg(self.heartbeat, self.rcv_buffer))
236 | rcv_data = self.receive(self.rcv_buffer, self.SOCK_MAX_TIMEOUT)
237 | if not rcv_data:
238 | raise BlynkError('Heartbeat stage timeout')
239 | _, _, status, _ = self.parse_response(rcv_data, self.rcv_buffer)
240 | if status != self.STATUS_OK:
241 | raise BlynkError('Set heartbeat returned code={}'.format(status))
242 | self.log('Heartbeat = {} sec. MaxCmdBuffer = {} bytes'.format(self.heartbeat, self.rcv_buffer))
243 |
244 | def connected(self):
245 | return True if self._state == self.AUTHENTICATED else False
246 |
247 |
248 | class Blynk(Connection):
249 | _CONNECT_TIMEOUT = 30 # 30sec
250 | _VPIN_WILDCARD = '*'
251 | _VPIN_READ = 'read v'
252 | _VPIN_WRITE = 'write v'
253 | _INTERNAL = 'internal_'
254 | _CONNECT = 'connect'
255 | _DISCONNECT = 'disconnect'
256 | _VPIN_READ_ALL = '{}{}'.format(_VPIN_READ, _VPIN_WILDCARD)
257 | _VPIN_WRITE_ALL = '{}{}'.format(_VPIN_WRITE, _VPIN_WILDCARD)
258 | _events = {}
259 |
260 | def __init__(self, token, **kwargs):
261 | Connection.__init__(self, token, **kwargs)
262 | self._start_time = ticks_ms()
263 | self._last_rcv_time = ticks_ms()
264 | self._last_send_time = ticks_ms()
265 | self._last_ping_time = ticks_ms()
266 | self._state = self.DISCONNECTED
267 | print(LOGO)
268 |
269 | def connect(self, timeout=_CONNECT_TIMEOUT):
270 | end_time = time.time() + timeout
271 | while not self.connected():
272 | if self._state == self.DISCONNECTED:
273 | try:
274 | self._get_socket()
275 | self._authenticate()
276 | self._set_heartbeat()
277 | self._last_rcv_time = ticks_ms()
278 | self.log('Registered events: {}\n'.format(list(self._events.keys())))
279 | self.call_handler(self._CONNECT)
280 | return True
281 | except BlynkError as b_err:
282 | self.disconnect(b_err)
283 | sleep_ms(self.TASK_PERIOD_RES)
284 | except RedirectError as r_err:
285 | self.disconnect()
286 | self.server = r_err.server
287 | self.port = r_err.port
288 | sleep_ms(self.TASK_PERIOD_RES)
289 | if time.time() >= end_time:
290 | return False
291 |
292 | def disconnect(self, err_msg=None):
293 | self.call_handler(self._DISCONNECT)
294 | if self._socket:
295 | self._socket.close()
296 | self._state = self.DISCONNECTED
297 | if err_msg:
298 | self.log('[ERROR]: {}\nConnection closed'.format(err_msg))
299 | self._msg_id = 0
300 | time.sleep(self.RECONNECT_SLEEP)
301 |
302 | def virtual_write(self, v_pin, *val):
303 | return self.send(self.virtual_write_msg(v_pin, *val))
304 |
305 | def virtual_sync(self, *v_pin):
306 | return self.send(self.virtual_sync_msg(*v_pin))
307 |
308 | def email(self, to, subject, body):
309 | return self.send(self.email_msg(to, subject, body))
310 |
311 | def tweet(self, msg):
312 | return self.send(self.tweet_msg(msg))
313 |
314 | def notify(self, msg):
315 | return self.send(self.notify_msg(msg))
316 |
317 | def set_property(self, v_pin, property_name, *val):
318 | return self.send(self.set_property_msg(v_pin, property_name, *val))
319 |
320 | def internal(self, *args):
321 | return self.send(self.internal_msg(*args))
322 |
323 | def handle_event(blynk, event_name):
324 | class Deco(object):
325 | def __init__(self, func):
326 | self.func = func
327 | # wildcard 'read V*' and 'write V*' events handling
328 | if str(event_name).lower() in (blynk._VPIN_READ_ALL, blynk._VPIN_WRITE_ALL):
329 | event_base_name = str(event_name).split(blynk._VPIN_WILDCARD)[0]
330 | for i in range(blynk.VPIN_MAX_NUM + 1):
331 | blynk._events['{}{}'.format(event_base_name.lower(), i)] = func
332 | else:
333 | blynk._events[str(event_name).lower()] = func
334 |
335 | def __call__(self):
336 | return self.func()
337 |
338 | return Deco
339 |
340 | def call_handler(self, event, *args, **kwargs):
341 | if event in self._events.keys():
342 | self.log("Event: ['{}'] -> {}".format(event, args))
343 | self._events[event](*args, **kwargs)
344 |
345 | def process(self, msg_type, msg_id, msg_len, msg_args):
346 | if msg_type == self.MSG_RSP:
347 | self.log('Response status: {}'.format(msg_len))
348 | elif msg_type == self.MSG_PING:
349 | self.send(self.response_msg(self.STATUS_OK, msg_id=msg_id))
350 | elif msg_type in (self.MSG_HW, self.MSG_BRIDGE, self.MSG_INTERNAL):
351 | if msg_type == self.MSG_INTERNAL:
352 | self.call_handler("{}{}".format(self._INTERNAL, msg_args[0]), msg_args[1:])
353 | elif len(msg_args) >= 3 and msg_args[0] == 'vw':
354 | self.call_handler("{}{}".format(self._VPIN_WRITE, msg_args[1]), int(msg_args[1]), msg_args[2:])
355 | elif len(msg_args) == 2 and msg_args[0] == 'vr':
356 | self.call_handler("{}{}".format(self._VPIN_READ, msg_args[1]), int(msg_args[1]))
357 |
358 | def read_response(self, timeout=0.5):
359 | end_time = time.time() + timeout
360 | while time.time() <= end_time:
361 | rsp_data = self.receive(self.rcv_buffer, self.SOCK_TIMEOUT)
362 | if rsp_data:
363 | self._last_rcv_time = ticks_ms()
364 | msg_type, msg_id, h_data, msg_args = self.parse_response(rsp_data, self.rcv_buffer)
365 | self.process(msg_type, msg_id, h_data, msg_args)
366 |
367 | def run(self):
368 | if not self.connected():
369 | self.connect()
370 | else:
371 | try:
372 | self.read_response(timeout=self.SOCK_TIMEOUT)
373 | if not self.is_server_alive():
374 | self.disconnect('Blynk server is offline')
375 | except KeyboardInterrupt:
376 | raise
377 | except BlynkError as b_err:
378 | self.log(b_err)
379 | self.disconnect()
380 | except Exception as g_exc:
381 | self.log(g_exc)
382 |
--------------------------------------------------------------------------------
/blynklib_mp.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2019-2020 Anton Morozenko
2 | # Copyright (c) 2015-2019 Volodymyr Shymanskyy.
3 | # See the file LICENSE for copying permission.
4 |
5 | __version__ = '0.2.6'
6 |
7 | import usocket as socket
8 | import utime as time
9 | import ustruct as struct
10 | import uselect as select
11 | from micropython import const
12 |
13 | ticks_ms = time.ticks_ms
14 | sleep_ms = time.sleep_ms
15 |
16 | IOError = OSError
17 |
18 | LOGO = """
19 | ___ __ __
20 | / _ )/ /_ _____ / /__
21 | / _ / / // / _ \\/ '_/
22 | /____/_/\\_, /_//_/_/\\_\\
23 | /___/ for Python v{}\n""".format(__version__)
24 |
25 |
26 | def stub_log(*args):
27 | pass
28 |
29 |
30 | class BlynkError(Exception):
31 | pass
32 |
33 |
34 | class RedirectError(Exception):
35 | def __init__(self, server, port):
36 | self.server = server
37 | self.port = port
38 |
39 |
40 | class Protocol(object):
41 | MSG_RSP = const(0)
42 | MSG_LOGIN = const(2)
43 | MSG_PING = const(6)
44 | MSG_TWEET = const(12)
45 | MSG_EMAIL = const(13)
46 | MSG_NOTIFY = const(14)
47 | MSG_BRIDGE = const(15)
48 | MSG_HW_SYNC = const(16)
49 | MSG_INTERNAL = const(17)
50 | MSG_PROPERTY = const(19)
51 | MSG_HW = const(20)
52 | MSG_REDIRECT = const(41)
53 | MSG_HEAD_LEN = const(5)
54 |
55 | STATUS_INVALID_TOKEN = const(9)
56 | STATUS_OK = const(200)
57 | VPIN_MAX_NUM = const(32)
58 |
59 | _msg_id = 1
60 |
61 | def _get_msg_id(self, **kwargs):
62 | if 'msg_id' in kwargs:
63 | return kwargs['msg_id']
64 | self._msg_id += const(1)
65 | return self._msg_id if self._msg_id <= const(0xFFFF) else const(1)
66 |
67 | def _pack_msg(self, msg_type, *args, **kwargs):
68 | data = ('\0'.join([str(curr_arg) for curr_arg in args])).encode('utf-8')
69 | return struct.pack('!BHH', msg_type, self._get_msg_id(**kwargs), len(data)) + data
70 |
71 | def parse_response(self, rsp_data, msg_buffer):
72 | msg_args = []
73 | msg_len = 0
74 | try:
75 | msg_type, msg_id, h_data = struct.unpack('!BHH', rsp_data[:self.MSG_HEAD_LEN])
76 | msg_len = self.MSG_HEAD_LEN + h_data
77 | except Exception as p_err:
78 | raise BlynkError('Message parse error: {}'.format(p_err))
79 | if msg_id == 0:
80 | raise BlynkError('invalid msg_id == 0')
81 | elif h_data >= msg_buffer:
82 | raise BlynkError('Command too long. Length = {}'.format(h_data))
83 | elif msg_type in (self.MSG_RSP, self.MSG_PING):
84 | pass
85 | elif msg_type in (self.MSG_HW, self.MSG_BRIDGE, self.MSG_INTERNAL, self.MSG_REDIRECT):
86 | msg_body = rsp_data[self.MSG_HEAD_LEN: msg_len]
87 | msg_args = [itm.decode('utf-8') for itm in msg_body.split(b'\0')]
88 | else:
89 | raise BlynkError("Unknown message type: '{}'".format(msg_type))
90 | return msg_type, msg_id, h_data, msg_args, msg_len
91 |
92 | def heartbeat_msg(self, heartbeat, rcv_buffer):
93 | return self._pack_msg(self.MSG_INTERNAL, 'ver', __version__, 'buff-in', rcv_buffer, 'h-beat', heartbeat,
94 | 'dev', 'mpython')
95 |
96 | def login_msg(self, token):
97 | return self._pack_msg(self.MSG_LOGIN, token)
98 |
99 | def ping_msg(self):
100 | return self._pack_msg(self.MSG_PING)
101 |
102 | def response_msg(self, *args, **kwargs):
103 | return self._pack_msg(self.MSG_RSP, *args, **kwargs)
104 |
105 | def virtual_write_msg(self, v_pin, *val):
106 | return self._pack_msg(self.MSG_HW, 'vw', v_pin, *val)
107 |
108 | def virtual_sync_msg(self, *pins):
109 | return self._pack_msg(self.MSG_HW_SYNC, 'vr', *pins)
110 |
111 | def email_msg(self, to, subject, body):
112 | return self._pack_msg(self.MSG_EMAIL, to, subject, body)
113 |
114 | def tweet_msg(self, msg):
115 | return self._pack_msg(self.MSG_TWEET, msg)
116 |
117 | def notify_msg(self, msg):
118 | return self._pack_msg(self.MSG_NOTIFY, msg)
119 |
120 | def set_property_msg(self, pin, prop, *val):
121 | return self._pack_msg(self.MSG_PROPERTY, pin, prop, *val)
122 |
123 | def internal_msg(self, *args):
124 | return self._pack_msg(self.MSG_INTERNAL, *args)
125 |
126 |
127 | class Connection(Protocol):
128 | SOCK_MAX_TIMEOUT = const(5)
129 | SOCK_TIMEOUT = 0.05
130 | EAGAIN = const(11)
131 | ETIMEDOUT = const(60)
132 | RETRIES_TX_DELAY = const(2)
133 | RETRIES_TX_MAX_NUM = const(3)
134 | RECONNECT_SLEEP = const(1)
135 | TASK_PERIOD_RES = const(50)
136 | DISCONNECTED = const(0)
137 | CONNECTING = const(1)
138 | AUTHENTICATING = const(2)
139 | AUTHENTICATED = const(3)
140 |
141 | _state = None
142 | _socket = None
143 | _last_rcv_time = 0
144 | _last_ping_time = 0
145 | _last_send_time = 0
146 |
147 | def __init__(self, token, server='blynk-cloud.com', port=80, heartbeat=10, rcv_buffer=1024, log=stub_log):
148 | self.token = token
149 | self.server = server
150 | self.port = port
151 | self.heartbeat = heartbeat
152 | self.rcv_buffer = rcv_buffer
153 | self.log = log
154 |
155 | def _set_socket_timeout(self, timeout):
156 | if getattr(self._socket, 'settimeout', None):
157 | self._socket.settimeout(timeout)
158 | else:
159 | p = select.poll()
160 | p.register(self._socket)
161 | p.poll(int(timeout * const(1000)))
162 |
163 | def send(self, data):
164 | retries = self.RETRIES_TX_MAX_NUM
165 | while retries > 0:
166 | try:
167 | retries -= 1
168 | self._last_send_time = ticks_ms()
169 | return self._socket.send(data)
170 | except (IOError, OSError):
171 | sleep_ms(self.RETRIES_TX_DELAY)
172 |
173 | def receive(self, length, timeout):
174 | d_buff = b''
175 | try:
176 | self._set_socket_timeout(timeout)
177 | d_buff += self._socket.recv(length)
178 | if len(d_buff) >= length:
179 | d_buff = d_buff[:length]
180 | return d_buff
181 | except (IOError, OSError) as err:
182 | if str(err) == 'timed out':
183 | return b''
184 | if str(self.EAGAIN) in str(err) or str(self.ETIMEDOUT) in str(err):
185 | return b''
186 | raise
187 |
188 | def is_server_alive(self):
189 | now = ticks_ms()
190 | h_beat_ms = self.heartbeat * const(1000)
191 | rcv_delta = time.ticks_diff(now, self._last_rcv_time)
192 | ping_delta = time.ticks_diff(now, self._last_ping_time)
193 | send_delta = time.ticks_diff(now, self._last_send_time)
194 | if rcv_delta > h_beat_ms + (h_beat_ms // const(2)):
195 | return False
196 | if (ping_delta > h_beat_ms // const(10)) and (send_delta > h_beat_ms or rcv_delta > h_beat_ms):
197 | self.send(self.ping_msg())
198 | self.log('Heartbeat time: {}'.format(now))
199 | self._last_ping_time = now
200 | return True
201 |
202 | def _get_socket(self):
203 | try:
204 | self._state = self.CONNECTING
205 | self._socket = socket.socket()
206 | self._socket.connect(socket.getaddrinfo(self.server, self.port)[0][-1])
207 | self._set_socket_timeout(self.SOCK_TIMEOUT)
208 | self.log('Connected to server')
209 | except Exception as g_exc:
210 | raise BlynkError('Server connection failed: {}'.format(g_exc))
211 |
212 | def _authenticate(self):
213 | self.log('Authenticating device...')
214 | self._state = self.AUTHENTICATING
215 | self.send(self.login_msg(self.token))
216 | rsp_data = self.receive(self.rcv_buffer, self.SOCK_MAX_TIMEOUT)
217 | if not rsp_data:
218 | raise BlynkError('Auth stage timeout')
219 | msg_type, _, status, args, _ = self.parse_response(rsp_data, self.rcv_buffer)
220 | if status != self.STATUS_OK:
221 | if status == self.STATUS_INVALID_TOKEN:
222 | raise BlynkError('Invalid Auth Token')
223 | if msg_type == self.MSG_REDIRECT:
224 | raise RedirectError(*args)
225 | raise BlynkError('Auth stage failed. Status={}'.format(status))
226 | self._state = self.AUTHENTICATED
227 | self.log('Access granted')
228 |
229 | def _set_heartbeat(self):
230 | self.send(self.heartbeat_msg(self.heartbeat, self.rcv_buffer))
231 | rcv_data = self.receive(self.rcv_buffer, self.SOCK_MAX_TIMEOUT)
232 | if not rcv_data:
233 | raise BlynkError('Heartbeat stage timeout')
234 | _, _, status, _, _ = self.parse_response(rcv_data, self.rcv_buffer)
235 | if status != self.STATUS_OK:
236 | raise BlynkError('Set heartbeat returned code={}'.format(status))
237 | self.log('Heartbeat = {} sec. MaxCmdBuffer = {} bytes'.format(self.heartbeat, self.rcv_buffer))
238 |
239 | def connected(self):
240 | return True if self._state == self.AUTHENTICATED else False
241 |
242 |
243 | class Blynk(Connection):
244 | _CONNECT_TIMEOUT = const(30) # 30sec
245 | _VPIN_WILDCARD = '*'
246 | _VPIN_READ = 'read v'
247 | _VPIN_WRITE = 'write v'
248 | _INTERNAL = 'internal_'
249 | _CONNECT = 'connect'
250 | _DISCONNECT = 'disconnect'
251 | _VPIN_READ_ALL = '{}{}'.format(_VPIN_READ, _VPIN_WILDCARD)
252 | _VPIN_WRITE_ALL = '{}{}'.format(_VPIN_WRITE, _VPIN_WILDCARD)
253 | _events = {}
254 |
255 | def __init__(self, token, **kwargs):
256 | Connection.__init__(self, token, **kwargs)
257 | self._start_time = ticks_ms()
258 | self._last_rcv_time = ticks_ms()
259 | self._last_send_time = ticks_ms()
260 | self._last_ping_time = ticks_ms()
261 | self._state = self.DISCONNECTED
262 | print(LOGO)
263 |
264 | def connect(self, timeout=_CONNECT_TIMEOUT):
265 | end_time = time.time() + timeout
266 | while not self.connected():
267 | if self._state == self.DISCONNECTED:
268 | try:
269 | self._get_socket()
270 | self._authenticate()
271 | self._set_heartbeat()
272 | self._last_rcv_time = ticks_ms()
273 | self.log('Registered events: {}\n'.format(list(self._events.keys())))
274 | self.call_handler(self._CONNECT)
275 | return True
276 | except BlynkError as b_err:
277 | self.disconnect(b_err)
278 | sleep_ms(self.TASK_PERIOD_RES)
279 | except RedirectError as r_err:
280 | self.disconnect()
281 | self.server = r_err.server
282 | self.port = r_err.port
283 | sleep_ms(self.TASK_PERIOD_RES)
284 | if time.time() >= end_time:
285 | return False
286 |
287 | def disconnect(self, err_msg=None):
288 | self.call_handler(self._DISCONNECT)
289 | if self._socket:
290 | self._socket.close()
291 | self._state = self.DISCONNECTED
292 | if err_msg:
293 | self.log('[ERROR]: {}\nConnection closed'.format(err_msg))
294 | time.sleep(self.RECONNECT_SLEEP)
295 |
296 | def virtual_write(self, v_pin, *val):
297 | return self.send(self.virtual_write_msg(v_pin, *val))
298 |
299 | def virtual_sync(self, *v_pin):
300 | return self.send(self.virtual_sync_msg(*v_pin))
301 |
302 | def email(self, to, subject, body):
303 | return self.send(self.email_msg(to, subject, body))
304 |
305 | def tweet(self, msg):
306 | return self.send(self.tweet_msg(msg))
307 |
308 | def notify(self, msg):
309 | return self.send(self.notify_msg(msg))
310 |
311 | def set_property(self, v_pin, property_name, *val):
312 | return self.send(self.set_property_msg(v_pin, property_name, *val))
313 |
314 | def internal(self, *args):
315 | return self.send(self.internal_msg(*args))
316 |
317 | def handle_event(blynk, event_name):
318 | class Deco(object):
319 | def __init__(self, func):
320 | self.func = func
321 | # wildcard 'read V*' and 'write V*' events handling
322 | if str(event_name).lower() in (blynk._VPIN_READ_ALL, blynk._VPIN_WRITE_ALL):
323 | event_base_name = str(event_name).split(blynk._VPIN_WILDCARD)[0]
324 | for i in range(blynk.VPIN_MAX_NUM + 1):
325 | blynk._events['{}{}'.format(event_base_name.lower(), i)] = func
326 | else:
327 | blynk._events[str(event_name).lower()] = func
328 |
329 | def __call__(self):
330 | return self.func()
331 |
332 | return Deco
333 |
334 | def call_handler(self, event, *args, **kwargs):
335 | if event in self._events.keys():
336 | self.log("Event: ['{}'] -> {}".format(event, args))
337 | self._events[event](*args, **kwargs)
338 |
339 | def process(self, msg_type, msg_id, msg_len, msg_args):
340 | if msg_type == self.MSG_RSP:
341 | self.log('Response status: {}'.format(msg_len))
342 | elif msg_type == self.MSG_PING:
343 | self.send(self.response_msg(self.STATUS_OK, msg_id=msg_id))
344 | elif msg_type in (self.MSG_HW, self.MSG_BRIDGE, self.MSG_INTERNAL):
345 | if msg_type == self.MSG_INTERNAL:
346 | self.call_handler("{}{}".format(self._INTERNAL, msg_args[0]), msg_args[1:])
347 | elif len(msg_args) >= const(3) and msg_args[0] == 'vw':
348 | self.call_handler("{}{}".format(self._VPIN_WRITE, msg_args[1]), int(msg_args[1]), msg_args[2:])
349 | elif len(msg_args) == const(2) and msg_args[0] == 'vr':
350 | self.call_handler("{}{}".format(self._VPIN_READ, msg_args[1]), int(msg_args[1]))
351 |
352 | def read_response(self, timeout=0.5):
353 | end_time = time.ticks_ms() + int(timeout * const(1000))
354 | while time.ticks_diff(end_time, time.ticks_ms()) > 0:
355 | rsp_data = self.receive(self.rcv_buffer, self.SOCK_TIMEOUT)
356 | if rsp_data:
357 | self._last_rcv_time = ticks_ms()
358 | while rsp_data:
359 | msg_type, msg_id, h_data, msg_args, msg_len = self.parse_response(rsp_data, self.rcv_buffer)
360 | self.process(msg_type, msg_id, h_data, msg_args)
361 | rsp_data = rsp_data[msg_len:]
362 |
363 | def run(self):
364 | if not self.connected():
365 | self.connect()
366 | else:
367 | try:
368 | self.read_response(timeout=self.SOCK_TIMEOUT)
369 | if not self.is_server_alive():
370 | self.disconnect('Server is offline')
371 | except KeyboardInterrupt:
372 | raise
373 | except BlynkError as b_err:
374 | self.log(b_err)
375 | self.disconnect()
376 | except Exception as g_exc:
377 | self.log(g_exc)
378 |
--------------------------------------------------------------------------------
/blynktimer.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2019-2020 Anton Morozenko
2 | """
3 | Polling timers for functions.
4 | Registers timers and performs run once or periodical function execution after defined time intervals.
5 | """
6 | # select.select call used as polling waiter where it is possible
7 | # cause time.sleep sometimes may load CPU up to 100% with small polling wait interval
8 | try:
9 | # cpython
10 | import time
11 | import select
12 |
13 | polling_wait = lambda x: select.select([], [], [], x)
14 | polling_wait(0.01)
15 | except OSError:
16 | # windows case where select.select call fails
17 | polling_wait = lambda x: time.sleep(x)
18 |
19 | except ImportError:
20 | # micropython
21 | import utime as time
22 |
23 | try:
24 | from uselect import select as s_select
25 |
26 | polling_wait = lambda x: s_select([], [], [], x)
27 | except ImportError:
28 | # case when micropython port does not support select.select
29 | polling_wait = lambda x: time.sleep(x)
30 |
31 | WAIT_SEC = 0.05
32 | MAX_TIMERS = 16
33 | DEFAULT_INTERVAL = 10
34 |
35 |
36 | class TimerError(Exception):
37 | pass
38 |
39 |
40 | class Timer(object):
41 | timers = {}
42 |
43 | def __init__(self, no_timers_err=True):
44 | self.no_timers_err = no_timers_err
45 |
46 | def _get_func_name(self, obj):
47 | """retrieves a suitable name for a function"""
48 | if hasattr(obj, 'func'):
49 | # handles nested decorators
50 | return self._get_func_name(obj.func)
51 | # simply returns 'timer' if on port without function attrs
52 | return getattr(obj, '__name__', 'timer')
53 |
54 | def register(blynk, *args, **kwargs):
55 | # kwargs with defaults are used cause PEP 3102 no supported by Python2
56 | interval = kwargs.pop('interval', DEFAULT_INTERVAL)
57 | run_once = kwargs.pop('run_once', False)
58 | stopped = kwargs.pop('stopped', False)
59 |
60 | class Deco(object):
61 | def __init__(self, func):
62 | self.func = func
63 | if len(list(Timer.timers.keys())) >= MAX_TIMERS:
64 | raise TimerError('Max allowed timers num={}'.format(MAX_TIMERS))
65 | _timer = _Timer(interval, func, run_once, stopped, *args, **kwargs)
66 | Timer.timers['{}_{}'.format(len(list(Timer.timers.keys())), blynk._get_func_name(func))] = _timer
67 |
68 | def __call__(self, *f_args, **f_kwargs):
69 | return self.func(*f_args, **f_kwargs)
70 |
71 | return Deco
72 |
73 | @staticmethod
74 | def stop(t_id):
75 | timer = Timer.timers.get(t_id, None)
76 | if timer is None:
77 | raise TimerError('Timer id={} not found'.format(t_id))
78 | Timer.timers[t_id].stopped = True
79 |
80 | @staticmethod
81 | def start(t_id):
82 | timer = Timer.timers.get(t_id, None)
83 | if timer is None:
84 | raise TimerError('Timer id={} not found'.format(t_id))
85 | Timer.timers[t_id].stopped = False
86 | Timer.timers[t_id].fire_time = None
87 | Timer.timers[t_id].fire_time_prev = None
88 |
89 | @staticmethod
90 | def is_stopped(t_id):
91 | timer = Timer.timers.get(t_id, None)
92 | if timer is None:
93 | raise TimerError('Timer id={} not found'.format(t_id))
94 | return timer.stopped
95 |
96 | def get_timers(self):
97 | states = {True: 'Stopped', False: 'Running'}
98 | return {k: states[v.stopped] for k, v in self.timers.items()}
99 |
100 | def run(self):
101 | polling_wait(WAIT_SEC)
102 | timers_intervals = [curr_timer.run() for curr_timer in Timer.timers.values() if not curr_timer.stopped]
103 | if not timers_intervals and self.no_timers_err:
104 | raise TimerError('Running timers not found')
105 | return timers_intervals
106 |
107 |
108 | class _Timer(object):
109 | def __init__(self, interval, deco, run_once, stopped, *args, **kwargs):
110 | self.interval = interval
111 | self.deco = deco
112 | self.args = args
113 | self.run_once = run_once
114 | self.kwargs = kwargs
115 | self.fire_time = None
116 | self.fire_time_prev = None
117 | self.stopped = stopped
118 |
119 | def run(self):
120 | timer_real_interval = 0
121 | if self.fire_time is None:
122 | self.fire_time = time.time() + self.interval
123 | if self.fire_time_prev is None:
124 | self.fire_time_prev = time.time()
125 | curr_time = time.time()
126 | if curr_time >= self.fire_time:
127 | self.deco(*self.args, **self.kwargs)
128 | if self.run_once:
129 | self.stopped = True
130 | timer_real_interval = curr_time - self.fire_time_prev
131 | self.fire_time_prev = self.fire_time
132 | self.fire_time = curr_time + self.interval
133 | return timer_real_interval
134 |
--------------------------------------------------------------------------------
/certificate/blynk-cloud.com.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIID5TCCAs2gAwIBAgIJAIHSnb+cv4ECMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD
3 | VQQGEwJVQTENMAsGA1UECAwES3lpdjENMAsGA1UEBwwES3lpdjELMAkGA1UECgwC
4 | SVQxEzARBgNVBAsMCkJseW5rIEluYy4xGDAWBgNVBAMMD2JseW5rLWNsb3VkLmNv
5 | bTEfMB0GCSqGSIb3DQEJARYQZG1pdHJpeUBibHluay5jYzAeFw0xNjAzMTcxMTU4
6 | MDdaFw0yMTAzMTYxMTU4MDdaMIGIMQswCQYDVQQGEwJVQTENMAsGA1UECAwES3lp
7 | djENMAsGA1UEBwwES3lpdjELMAkGA1UECgwCSVQxEzARBgNVBAsMCkJseW5rIElu
8 | Yy4xGDAWBgNVBAMMD2JseW5rLWNsb3VkLmNvbTEfMB0GCSqGSIb3DQEJARYQZG1p
9 | dHJpeUBibHluay5jYzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALso
10 | bhbXQuNlzYBFa9h9pd69n43yrGTL4Ba6k5Q1zDwY9HQbMdfC5ZfnCkqT7Zf+R5MO
11 | RW0Q9nLsFNLJkwKnluRCYGyUES8NAmDLQBbZoVc8mv9K3mIgAQvGyY2LmKak5GSI
12 | V0PC3x+iN03xU2774+Zi7DaQd7vTl/9RGk8McyHe/s5Ikbe14bzWcY9ZV4PKgCck
13 | p1chbmLhSfGbT3v64sL8ZbIppQk57/JgsZMrVpjExvxQPZuJfWbtoypPfpYO+O8l
14 | 1szaMlTEPIZVMoYi9uE+DnOlhzJFn6Ac4FMrDzJXzMmCweSX3IxguvXALeKhUHQJ
15 | +VP3G6Q3pkZRVKz+5XsCAwEAAaNQME4wHQYDVR0OBBYEFJtqtI62Io66cZgiTR5L
16 | A5Tl5m+xMB8GA1UdIwQYMBaAFJtqtI62Io66cZgiTR5LA5Tl5m+xMAwGA1UdEwQF
17 | MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKphjtEOGs7oC3S87+AUgIw4gFNOuv+L
18 | C98/l47OD6WtsqJKvCZ1lmKxY5aIro9FBPk8ktCOsbwEjE+nyr5wul+6CLFr+rnv
19 | 7OHYGwLpjoz+rZgYJiQ61E1m0AZ4y9Fyd+D90HW6247vrBXyEiUXOhN/oDDVfDQA
20 | eqmNBx1OqWel81D3tA7zPMA7vUItyWcFIXNjOCP+POy7TMxZuhuPMh5bVu+/cthl
21 | /Q9u/Z2lKl4CWV0Ivt2BtlN6iefva0e2AP/As+gfwjxrb0t11zSILLNJ+nxRIwg+
22 | k4MGb1zihKbIXUzsjslONK4FY5rlQUSwKJgEAVF0ClxB4g6dECm0ckc=
23 | -----END CERTIFICATE-----
24 |
--------------------------------------------------------------------------------
/examples/01_write_virtual_pin.py:
--------------------------------------------------------------------------------
1 | """
2 | [WRITE VIRTUAL PIN EXAMPLE] ========================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "Slider" widget,
7 | - bind it to Virtual Pin V4,
8 | - set values range 0-255
9 | - add "LED" widget and assign Virtual Pin V4 to it
10 | - Run the App (green triangle in the upper right corner).
11 | - define your auth token for current example and run it
12 |
13 |
14 | This started program will periodically call and execute event handler "write_virtual_pin_handler".
15 | In app you can move slider that will cause LED brightness change and will send virtual write event
16 | to current running example. Handler will print pin number and it's updated value.
17 |
18 | Schema:
19 | ====================================================================================================
20 | +-----------+ +--------------+ +--------------+
21 | | | | | | |
22 | | blynk lib | | blynk server | | blynk app |
23 | | | | virtual pin | | |
24 | | | | | | |
25 | +-----+-----+ +------+-------+ +-------+------+
26 | | | |
27 | | | write event from "Slider" widget |
28 | | | |
29 | | +<-----------------------------------+
30 | | | |
31 | | | |
32 | | | |
33 | | | |
34 | event handler | write event to hw from server | |
35 | (user function) | | |
36 | +-----------<------------------------------------+ |
37 | | | | |
38 | | | | |
39 | +--------->+ | |
40 | | | |
41 | | | |
42 | | | |
43 | + + +
44 | ====================================================================================================
45 | Additional blynk info you can find by examining such resources:
46 |
47 | Downloads, docs, tutorials: https://blynk.io
48 | Sketch generator: http://examples.blynk.cc
49 | Blynk community: http://community.blynk.cc
50 | Social networks: http://www.fb.com/blynkapp
51 | http://twitter.com/blynk_app
52 | ====================================================================================================
53 | """
54 |
55 | import blynklib
56 |
57 | BLYNK_AUTH = 'YourAuthToken'
58 |
59 | # initialize Blynk
60 | blynk = blynklib.Blynk(BLYNK_AUTH)
61 |
62 | WRITE_EVENT_PRINT_MSG = "[WRITE_VIRTUAL_PIN_EVENT] Pin: V{} Value: '{}'"
63 |
64 |
65 | # register handler for virtual pin V4 write event
66 | @blynk.handle_event('write V4')
67 | def write_virtual_pin_handler(pin, value):
68 | print(WRITE_EVENT_PRINT_MSG.format(pin, value))
69 |
70 |
71 | ###########################################################
72 | # infinite loop that waits for event
73 | ###########################################################
74 | while True:
75 | blynk.run()
76 |
--------------------------------------------------------------------------------
/examples/02_read_virtual_pin.py:
--------------------------------------------------------------------------------
1 | """
2 | [READ VIRTUAL PIN EXAMPLE] ========================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "Value Display" widget,
7 | - bind it to Virtual Pin V11,
8 | - set values range 0-255
9 | - set the read frequency to 5 second.
10 | - optionally to have more visibility you can add "LED" widget and assign Virtual Pin V11 to it
11 | - Run the App (green triangle in the upper right corner).
12 | - define your auth token for current example and run it
13 |
14 |
15 | This started program will periodically call and execute event handler "read_virtual_pin_handler".
16 | Calling virtual_write operation inside handler updates widget value.
17 | In app you can see updated values and optionally LED brightness change.
18 |
19 | Schema:
20 | =====================================================================================================
21 | +-----------+ +--------------+ +--------------+
22 | | | | | | |
23 | | blynk lib | | blynk server | | blynk app |
24 | | | | virtual pin | | |
25 | | | | | | |
26 | +-----------+ +--------------+ +--------------+
27 | | | |
28 | | | |
29 | | | widget read frequency = 5 sec |
30 | | +<-----------------------------------+
31 | | | |
32 | | | |
33 | | | send virtual pin value to widget |
34 | | | |
35 | event handler | read event to hw from server +----------------------------------->+
36 | (user function) | | |
37 | +-----------<------------------------------------+ |
38 | | | | |
39 | | | write random 0-255 value to pin | |
40 | +--------->------------------------------------->+ next widget read event |
41 | | | |
42 | | +<-----------------------------------+
43 | | | |
44 | | | |
45 | + + +
46 |
47 | ====================================================================================================
48 | Additional info about blynk you can find by examining such resources:
49 |
50 | Downloads, docs, tutorials: https://blynk.io
51 | Sketch generator: http://examples.blynk.cc
52 | Blynk community: http://community.blynk.cc
53 | Social networks: http://www.fb.com/blynkapp
54 | http://twitter.com/blynk_app
55 | =====================================================================================================
56 | """
57 |
58 | import blynklib
59 | import random
60 |
61 | BLYNK_AUTH = 'YourAuthToken'
62 |
63 | # initialize blynk
64 | blynk = blynklib.Blynk(BLYNK_AUTH)
65 |
66 | READ_PRINT_MSG = "[READ_VIRTUAL_PIN_EVENT] Pin: V{}"
67 |
68 |
69 | # register handler for virtual pin V11 reading
70 | @blynk.handle_event('read V11')
71 | def read_virtual_pin_handler(pin):
72 | print(READ_PRINT_MSG.format(pin))
73 | blynk.virtual_write(pin, random.randint(0, 255))
74 |
75 |
76 | ###########################################################
77 | # infinite loop that waits for event
78 | ###########################################################
79 | while True:
80 | blynk.run()
81 |
--------------------------------------------------------------------------------
/examples/03_connect_disconnect.py:
--------------------------------------------------------------------------------
1 | """
2 | [CONNECT/DISCONNECT EVENTS EXAMPLE] =================================================================
3 |
4 | Environment prepare:
5 | - define your auth token for current example and run it
6 |
7 |
8 | This started program after successful connect operation will call and execute "connect event handler"
9 | Within handler after short sleep delay blynk disconnect call will be performed that will trigger
10 | "disconnect event handler" execution.
11 |
12 | Schema:
13 | =====================================================================================================
14 | +-----------+ +--------------+
15 | | | | |
16 | | blynk lib | | blynk server |
17 | | | | virtual pin |
18 | | | | |
19 | +-----+-----+ +------+-------+
20 | | |
21 | | connect/authenticate request |
22 | +------------------------------------>+
23 | connect handler | |
24 | (user function) | connected successfully |
25 | +-----------<------------------------------------+
26 | | | |
27 | | | disconnect request |
28 | +--------->------------------------------------->+
29 | | |
30 | | |
31 | disconnect handler | |
32 | (user function) | disconnected successfully |
33 | +-----------<------------------------------------+
34 | | | |
35 | | | |
36 | +--------->+ |
37 | | reconnect request |
38 | | performed by lib automatically |
39 | +------------------------------------>+
40 | + +
41 |
42 |
43 | ====================================================================================================
44 | Additional info about blynk you can find by examining such resources:
45 |
46 | Downloads, docs, tutorials: https://blynk.io
47 | Sketch generator: http://examples.blynk.cc
48 | Blynk community: http://community.blynk.cc
49 | Social networks: http://www.fb.com/blynkapp
50 | http://twitter.com/blynk_app
51 | =====================================================================================================
52 | """
53 |
54 | import blynklib
55 | import time
56 |
57 | BLYNK_AUTH = 'YourAuthToken'
58 |
59 | blynk = blynklib.Blynk(BLYNK_AUTH)
60 |
61 | CONNECT_PRINT_MSG = '[CONNECT_EVENT]'
62 | DISCONNECT_PRINT_MSG = '[DISCONNECT_EVENT]'
63 |
64 |
65 | @blynk.handle_event("connect")
66 | def connect_handler():
67 | print(CONNECT_PRINT_MSG)
68 | print('Sleeping 2 sec in connect handler...')
69 | time.sleep(2)
70 | blynk.disconnect()
71 |
72 |
73 | @blynk.handle_event("disconnect")
74 | def disconnect_handler():
75 | print(DISCONNECT_PRINT_MSG)
76 | print('Sleeping 4 sec in disconnect handler...')
77 | time.sleep(4)
78 |
79 |
80 | ###########################################################
81 | # infinite loop that waits for event
82 | ###########################################################
83 | while True:
84 | blynk.run()
85 |
--------------------------------------------------------------------------------
/examples/04_email.py:
--------------------------------------------------------------------------------
1 | """
2 | [EMAIL ON CONNECT EXAMPLE] ==========================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "Email" widget,
7 | - Run the App (green triangle in the upper right corner).
8 | - define for current example your target email.
9 | - define your auth token for current example and run it
10 |
11 |
12 | This started program will operate with "connect_handler".
13 | Within handler after short sleep delay email send operation will be performed.
14 |
15 | Schema:
16 | =====================================================================================================================
17 | +-----------+ +--------------+ +--------------+ +-------+
18 | | | | | | | | |
19 | | blynk lib | | blynk server | | blynk app | | email |
20 | | | | virtual pin | | | | box |
21 | | | | | | | | |
22 | +-----+-----+ +------+-------+ +-------+------+ +---+----
23 | | connect request | | |
24 | +------------------------------------>+ | |
25 | connect handler | | | |
26 | (user function) | connected successfully | | |
27 | +-----------<------------------------------------+ | |
28 | | | | | |
29 | | | send email | email widget present? | |
30 | +--------->------------------------------------->+ (is user allowed to send emails) | |
31 | | +----------------------------------->+ |
32 | | | | |
33 | | | email sending allowed | |
34 | | +<-----------------------------------+ |
35 | | | | |
36 | | | | |
37 | | | send email to defined address | |
38 | | +----------------------------------------------------->+
39 | | | | |
40 | | | | |
41 | + + + +
42 |
43 |
44 | =====================================================================================================================
45 | Additional info about blynk you can find by examining such resources:
46 |
47 | Downloads, docs, tutorials: https://blynk.io
48 | Sketch generator: http://examples.blynk.cc
49 | Blynk community: http://community.blynk.cc
50 | Social networks: http://www.fb.com/blynkapp
51 | http://twitter.com/blynk_app
52 | =====================================================================================================================
53 | """
54 |
55 | import blynklib
56 | import time
57 |
58 | BLYNK_AUTH = 'YourAuthToken'
59 | TARGET_EMAIL = 'YourTargetEmail'
60 |
61 | blynk = blynklib.Blynk(BLYNK_AUTH)
62 | EMAIL_PRINT_MSG = "[EMAIL WAS SENT to '{}']".format(TARGET_EMAIL)
63 |
64 |
65 | @blynk.handle_event("connect")
66 | def connect_handler():
67 | print('Sleeping 2 sec before sending email...')
68 | time.sleep(2)
69 | blynk.email(TARGET_EMAIL, 'BLYNK-HW-TEST-EMAIL', 'Connected!')
70 | print(EMAIL_PRINT_MSG)
71 |
72 |
73 | ###########################################################
74 | # infinite loop that waits for event
75 | ###########################################################
76 | while True:
77 | blynk.run()
78 |
--------------------------------------------------------------------------------
/examples/05_set_property_notify.py:
--------------------------------------------------------------------------------
1 | """
2 | [SET_PROPERTY/NOTIFY EXAMPLE] ==========================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "Slider" widget,
7 | - bind it to Virtual Pin V5,
8 | - set values range 0-255
9 | - add "LED" widget and assign Virtual Pin V5 to it
10 | - add "Notification" widget to be allowed receive notifications in App
11 | - Run the App (green triangle in the upper right corner).
12 | - define your auth token for current example and run it
13 |
14 |
15 | This started program will periodically call and execute event handler "write_virtual_pin_handler".
16 | In app you can move slider that will cause LED brightness change and will send virtual write event
17 | to current running example. Handler will set random color for virtual pin and will send notification
18 | event to App. Virtual pin property 'color' change will cause color changes for "Slider" and "LED" widgets
19 | In App user will get notifications about color change event.
20 |
21 | Schema:
22 | =====================================================================================================================
23 | +-----------+ +--------------+ +--------------+
24 | | | | | | |
25 | | blynk lib | | blynk server | | blynk app |
26 | | | | virtual pin | | |
27 | | | | | | |
28 | +-----+-----+ +------+-------+ +-------+------+
29 | | | |
30 | | | write event from "Slider" widget |
31 | | | |
32 | | +<-----------------------------------+
33 | | | |
34 | | | |
35 | | | |
36 | | | |
37 | event handler | write event to hw from server | |
38 | (user function) | | |
39 | +-----------<------------------------------------+ |
40 | | | | |
41 | | | pin set property | pin property changed msg |
42 | +-----+--->------------------------------------->------------------------------------>+
43 | | | | |
44 | | | send notification | notification widget present? |
45 | +--->------------------------------------->------------------------------------>+
46 | | | |
47 | | | yes |
48 | | +<-----------------------------------+
49 | | | |
50 | | | |
51 | | +----------------------------------->+
52 | + + notification delivery +
53 |
54 | =====================================================================================================================
55 | Additional info about blynk you can find by examining such resources:
56 |
57 | Downloads, docs, tutorials: https://blynk.io
58 | Sketch generator: http://examples.blynk.cc
59 | Blynk community: http://community.blynk.cc
60 | Social networks: http://www.fb.com/blynkapp
61 | http://twitter.com/blynk_app
62 | =====================================================================================================================
63 | """
64 |
65 | import blynklib
66 | import random
67 |
68 | BLYNK_AUTH = 'YourAuthToken'
69 | blynk = blynklib.Blynk(BLYNK_AUTH)
70 |
71 | NOTIFY_MSG = "['COLOR' = '{}']"
72 | colors = {'#FF00FF': 'Magenta', '#00FF00': 'Lime'}
73 |
74 |
75 | @blynk.handle_event('write V5')
76 | def write_handler(pin, value):
77 | current_color = random.choice(list(colors.keys()))
78 | blynk.set_property(pin, 'color', current_color)
79 | blynk.notify(NOTIFY_MSG.format(colors[current_color]))
80 | print(NOTIFY_MSG.format(colors[current_color]))
81 |
82 |
83 | ###########################################################
84 | # infinite loop that waits for event
85 | ###########################################################
86 | while True:
87 | blynk.run()
88 |
--------------------------------------------------------------------------------
/examples/06_terminal_widget.py:
--------------------------------------------------------------------------------
1 | """
2 | [TERMINAL WIDGET EXAMPLE] ==========================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "Terminal" widget,
7 | - bind it to Virtual Pin V6,
8 | - add input line option in widget settings
9 | - Run the App (green triangle in the upper right corner).
10 | - define your auth token for current example
11 | - optionally you can define your own "ALLOWED_COMMANDS_LIST"
12 | - run current example
13 |
14 |
15 | This started program will periodically call and execute event handler "write_virtual_pin_handler".
16 | In App Terminal widget you can type commands. If command present in allowed list, script will try
17 | to execute it in current running environment and will send back to terminal execution results.
18 | Additionally can be used 'help' command to get in terminal list of available commands.
19 |
20 | Schema:
21 | =====================================================================================================================
22 | +-----+ +-----------+ +--------------+ +--------------+
23 | | | | | | | | |
24 | | env | | blynk lib | | blynk server | | blynk app |
25 | | | | | | virtual pin | | |
26 | | | | | | | | |
27 | +--+--+ +-----+-----+ +------+-------+ +-------+------+
28 | | | | |
29 | | | | write command from terminal widget |
30 | | | | |
31 | | | +<-----------------------------------+
32 | | event handler | write event to hw from server | |
33 | | (user function) | | |
34 | | exec +-----------<------------------------------------+ |
35 | +<----------+ | | |
36 | | | | write cmd out back to pin | |
37 | +---------->+--------->------------------------------------->+ |
38 | | | | was pin updated? |
39 | | | +<-----------------------------------+
40 | | | | |
41 | | | | |
42 | | | | take vpin data to widget output |
43 | | | | |
44 | | | +----------------------------------->+
45 | | | | |
46 | + + + +
47 |
48 | =====================================================================================================================
49 | Additional info about blynk you can find by examining such resources:
50 |
51 | Downloads, docs, tutorials: https://blynk.io
52 | Sketch generator: http://examples.blynk.cc
53 | Blynk community: http://community.blynk.cc
54 | Social networks: http://www.fb.com/blynkapp
55 | http://twitter.com/blynk_app
56 | =====================================================================================================================
57 | """
58 |
59 | import blynklib
60 | import subprocess
61 |
62 | BLYNK_AUTH = 'YourAuthToken'
63 |
64 | # last command in example - just to show error handling
65 | # for certain HW can be added specific commands. 'gpio readall' on PI3b for example
66 | ALLOWED_COMMANDS_LIST = ['ls', 'lsusb', 'ip a', 'ip abc']
67 |
68 | blynk = blynklib.Blynk(BLYNK_AUTH)
69 |
70 |
71 | @blynk.handle_event('write V6')
72 | def write_handler(pin, values):
73 | header = ''
74 | result = ''
75 | delimiter = '{}\n'.format('=' * 30)
76 | if values and values[0] in ALLOWED_COMMANDS_LIST:
77 | cmd_params = values[0].split(' ')
78 | try:
79 | result = subprocess.check_output(cmd_params).decode('utf-8')
80 | header = '[output]\n'
81 | except subprocess.CalledProcessError as exe_err:
82 | header = '[error]\n'
83 | result = 'Return Code: {}\n'.format(exe_err.returncode)
84 | except Exception as g_err:
85 | print("Command caused '{}'".format(g_err))
86 | elif values and values[0] == 'help':
87 | header = '[help -> allowed commands]\n'
88 | result = '{}\n'.format('\n'.join(ALLOWED_COMMANDS_LIST))
89 |
90 | # communicate with terminal if help or some allowed command
91 | if result:
92 | output = '{}{}{}{}'.format(header, delimiter, result, delimiter)
93 | print(output)
94 | blynk.virtual_write(pin, output)
95 | blynk.virtual_write(pin, '\n')
96 |
97 |
98 | ###########################################################
99 | # infinite loop that waits for event
100 | ###########################################################
101 | while True:
102 | blynk.run()
103 |
--------------------------------------------------------------------------------
/examples/07_tweet_and_logging.py:
--------------------------------------------------------------------------------
1 | """
2 | [TWEET AND LOGGING EXAMPLE] =========================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "Slider" widget,
7 | - bind it to Virtual Pin V7,
8 | - set values range 0-255
9 | - add "Twitter Settings" widget
10 | - connect via this widget to your twitter account.
11 | - Run the App (green triangle in the upper right corner).
12 | - define your auth token for current example and run it
13 |
14 |
15 | This started program will periodically call and execute event handler "write_virtual_pin_handler".
16 | In App you can move slider that send virtual write event to current running example.
17 | Handler will log to console this event and additionally will send tweet message with pin number and it's updated value.
18 |
19 | Schema:
20 | =====================================================================================================================
21 | +-----------+ +--------------+ +--------------+ +---------+
22 | | | | | | | | |
23 | | blynk lib | | blynk server | | blynk app | | twitter |
24 | | | | virtual pin | | | | |
25 | | | | | | | | |
26 | +-----+-----+ +------+-------+ +-------+------+ +----+----+
27 | | | | tweet widget |
28 | | | | auth |
29 | | | +--------------->+
30 | | | | ok |
31 | | | write event from "Slider" widget +<---------------+
32 | | | | |
33 | | +<-----------------------------------+ |
34 | | | | |
35 | event handler | write event to hw from server | | |
36 | (user function) | | | |
37 | +-----------<------------------------------------+ | |
38 | | | | | |
39 | | | msg for tweet widget | | |
40 | +--------->-------------------------------------------------------------------------->+ |
41 | | | | real tweet msg |
42 | | | +--------------->+
43 | | | | |
44 | + + + +
45 |
46 | =====================================================================================================================
47 | Additional blynk info you can find by examining such resources:
48 |
49 | Downloads, docs, tutorials: https://blynk.io
50 | Sketch generator: http://examples.blynk.cc
51 | Blynk community: http://community.blynk.cc
52 | Social networks: http://www.fb.com/blynkapp
53 | http://twitter.com/blynk_app
54 | =====================================================================================================================
55 | """
56 | # uncomment line below if simple printing will be used instead of logging
57 | # from __future__ import print_function
58 | import blynklib
59 | import logging
60 |
61 | # tune console logging
62 | _log = logging.getLogger('BlynkLog')
63 | logFormatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
64 | consoleHandler = logging.StreamHandler()
65 | consoleHandler.setFormatter(logFormatter)
66 | _log.addHandler(consoleHandler)
67 | _log.setLevel(logging.DEBUG)
68 |
69 | # uncomment line below if simple printing will be used instead of logging
70 | # _log.info = print
71 |
72 | BLYNK_AUTH = 'YourAuthToken'
73 | blynk = blynklib.Blynk(BLYNK_AUTH, log=_log.info)
74 |
75 | # uncomment line below if simple printing will be used instead of logging
76 | # blynk = blynklib.Blynk(BLYNK_AUTH, log=print)
77 |
78 | WRITE_EVENT_PRINT_MSG = "[WRITE_VIRTUAL_PIN_EVENT] Pin: V{} Value: '{}'"
79 | TWEET_MSG = "New value='{}' on VPIN({})"
80 |
81 |
82 | # register handler for all virtual pins (including V7).
83 | # So in one block here we can handle evens for vpins 0-32 (32 - Max allowed VPIN number in lib)
84 | @blynk.handle_event('write V*')
85 | def write_virtual_pin_handler(pin, value):
86 | _log.info(WRITE_EVENT_PRINT_MSG.format(pin, value))
87 | blynk.tweet(TWEET_MSG.format(pin, value))
88 |
89 |
90 | ###########################################################
91 | # infinite loop that waits for event
92 | ###########################################################
93 | while True:
94 | blynk.run()
95 |
--------------------------------------------------------------------------------
/examples/08_blynk_timer.py:
--------------------------------------------------------------------------------
1 | """
2 | [BLYNK TIMER EXAMPLE] ============================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "SuperChart" widget
7 | - add two data streams for it ( stream #1 - Virtual Pin 8, stream #2 - Virtual Pin 9)
8 | - set different colors for data stream (ex. red and orange)
9 | - Run the App (green triangle in the upper right corner).
10 | - define your auth token for current example and run it
11 |
12 |
13 | This started program will register two timers that will update Virtual Pins data after defined intervals.
14 | In app you can see on graph both pins data change. Additionally timers will print new pin values info to stdout.
15 |
16 | Schema:
17 | =================================================================================================================
18 | +-----------+ +--------------+ +--------------+
19 | | | | | | |
20 | | blynk lib | | blynk server | | blynk app |
21 | | | | virtual pin | | |
22 | | | | | | |
23 | +-----+-----+ +------+-------+ +-------+------+
24 | | | |
25 | | | |
26 | | | |
27 | | | |
28 | +------------+ | |
29 | | +---------+ | |
30 | | | | update virtual pin 8 value | |
31 | | | | | notify app about vpin 8 update |
32 | | +-------->------------------------------------->+ |
33 | | | +----------------------------------->+
34 | +----------->------------------------------------->+ |
35 | | +----------------------------------->+
36 | | update virtual pin 9 value | |
37 | | | notify app about vpin 9 update |
38 | | | |
39 | | | |
40 | | | |
41 | + + +
42 |
43 | ================================================================================================================
44 | Additional blynk info you can find by examining such resources:
45 |
46 | Downloads, docs, tutorials: https://blynk.io
47 | Sketch generator: http://examples.blynk.cc
48 | Blynk community: http://community.blynk.cc
49 | Social networks: http://www.fb.com/blynkapp
50 | http://twitter.com/blynk_app
51 | ====================================================================================================
52 | """
53 |
54 | import blynklib
55 | import blynktimer
56 | import random
57 |
58 | BLYNK_AUTH = 'YourAuthToken' # insert your Auth Token here
59 | blynk = blynklib.Blynk(BLYNK_AUTH)
60 |
61 | # create timers dispatcher instance
62 | timer = blynktimer.Timer()
63 |
64 | WRITE_EVENT_PRINT_MSG = "[WRITE_VIRTUAL_WRITE] Pin: V{} Value: '{}'"
65 |
66 |
67 | # Code below: register two timers for different pins with different intervals
68 | # run_once flag allows to run timers once or periodically
69 | @timer.register(vpin_num=8, interval=4, run_once=False)
70 | @timer.register(vpin_num=9, interval=7, run_once=False)
71 | def write_to_virtual_pin(vpin_num=1):
72 | value = random.randint(0, 20)
73 | print(WRITE_EVENT_PRINT_MSG.format(vpin_num, value))
74 | blynk.virtual_write(vpin_num, value)
75 |
76 |
77 | while True:
78 | blynk.run()
79 | timer.run()
80 |
--------------------------------------------------------------------------------
/examples/09_sync_virtual_pin.py:
--------------------------------------------------------------------------------
1 | """
2 | [VIRTUAL PIN SYNC EXAMPLE] ==========================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add 3 "Button" widgets,
7 | - bind then to Virtual Pins V0, V1, v2
8 | - set mode "SWITCH" for all of them
9 | - Run the App (green triangle in the upper right corner).
10 | - define your auth token for current example and run it
11 |
12 |
13 | This started program will restore on connect write_virtual_pin states and colors.
14 | Buttons states and colors can be modified during script run.
15 | If script was interrupted (KeyboardInterrupt) buttons colors will be changed to red.
16 | During next connect event ( script re-run) previous buttons states and colors will be restored.
17 |
18 | Schema:
19 | =====================================================================================================================
20 | +-----------+ +--------------+ +--------------+
21 | | | | | | |
22 | | blynk lib | | blynk server | | blynk app |
23 | | | | virtual pin | | |
24 | | | | | | |
25 | +-----+-----+ +------+-------+ +-------+------+
26 | connect handler | | |
27 | +--------+ | |
28 | | +------------------------------------>+ |
29 | | | virtual pin sync | |
30 | | +<------------------------------------+----------------------------------->+
31 | | | virtual pin write stored value | send pin value to app |
32 | | +<------------------------------------+----------------------------------->+
33 | | | virtual pin apply stored properties | send pin properties to app |
34 | +------->+ | |
35 | write handler | | |
36 | +--------+ +<-----------------------------------+
37 | | +<------------------------------------+ write event from button |
38 | +>------>+ write event form server | |
39 | | | |
40 | | | |
41 | disconnect | | |
42 | handler | | |
43 | +-------+ | |
44 | | +------------------------------------>+ |
45 | +------>+ set new virtual pin property | |
46 | | | |
47 | | | |
48 | | | |
49 | + + +
50 |
51 | =====================================================================================================================
52 | Additional info about blynk you can find by examining such resources:
53 |
54 | Downloads, docs, tutorials: https://blynk.io
55 | Sketch generator: http://examples.blynk.cc
56 | Blynk community: http://community.blynk.cc
57 | Social networks: http://www.fb.com/blynkapp
58 | http://twitter.com/blynk_app
59 | =====================================================================================================================
60 | """
61 | import logging
62 | import blynklib
63 |
64 | # tune console logging
65 | _log = logging.getLogger('BlynkLog')
66 | logFormatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
67 | consoleHandler = logging.StreamHandler()
68 | consoleHandler.setFormatter(logFormatter)
69 | _log.addHandler(consoleHandler)
70 | _log.setLevel(logging.DEBUG)
71 |
72 | colors = {'1': '#FFC300', '0': '#CCCCCC', 'OFFLINE': '#FF0000'}
73 |
74 | BLYNK_AUTH = 'YourAuthToken'
75 | blynk = blynklib.Blynk(BLYNK_AUTH, log=_log.info)
76 |
77 |
78 | @blynk.handle_event("connect")
79 | def connect_handler():
80 | _log.info('SCRIPT_START')
81 | for pin in range(3):
82 | _log.info('Syncing virtual pin {}'.format(pin))
83 | blynk.virtual_sync(pin)
84 |
85 | # within connect handler after each server send operation forced socket reading is required cause:
86 | # - we are not in script listening state yet
87 | # - without forced reading some portion of blynk server messages can be not delivered to HW
88 | blynk.read_response(timeout=0.5)
89 |
90 |
91 | @blynk.handle_event('write V*')
92 | def write_handler(pin, value):
93 | button_state = value[0]
94 | blynk.set_property(pin, 'color', colors[button_state])
95 |
96 |
97 | @blynk.handle_event("disconnect")
98 | def connect_handler():
99 | for pin in range(3):
100 | _log.info("Set 'OFFLINE' color for pin {}".format(pin))
101 | blynk.set_property(pin, 'color', colors['OFFLINE'])
102 |
103 |
104 | ###########################################################
105 | # infinite loop that waits for event
106 | ###########################################################
107 | try:
108 | while True:
109 | blynk.run()
110 | except KeyboardInterrupt:
111 | blynk.disconnect()
112 | _log.info('SCRIPT WAS INTERRUPTED')
113 |
--------------------------------------------------------------------------------
/examples/10_rtc_sync.py:
--------------------------------------------------------------------------------
1 | """
2 | [RTC EXAMPLE] ========================================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "RTC" widget,
7 | - set required TimeZone,
8 | - Run the App (green triangle in the upper right corner).
9 | - define your auth token for current example and run it
10 |
11 |
12 | This started program on connect will send rtc_sync call to server.
13 | RTC reply will be captured by "internal_rtc" handler
14 | UTC time with required timezone correction will be printed
15 |
16 | Schema:
17 | =====================================================================================================================
18 | +-----------+ +--------------+ +--------------+
19 | | | | | | |
20 | | blynk lib | | blynk server | | blynk app |
21 | | | | | | |
22 | | | | | | |
23 | +-----+-----+ +------+-------+ +-------+------+
24 | | | |
25 | connect handler | | |
26 | +-------+ | |
27 | | | | |
28 | | | rtc sync | |
29 | +------>------------------------------------->+ rtc widget present in app? |
30 | | +----------------------------------->+
31 | | | |
32 | | | yes rtc widget found |
33 | | rtc with timezone correction +<-----------------------------------+
34 | internal_rtc | | |
35 | handler +--------<------------------------------------+ |
36 | | | | |
37 | | | | |
38 | +------>+ | |
39 | | | |
40 | | | |
41 | + + +
42 | =====================================================================================================================
43 | Additional blynk info you can find by examining such resources:
44 |
45 | Downloads, docs, tutorials: https://blynk.io
46 | Sketch generator: http://examples.blynk.cc
47 | Blynk community: http://community.blynk.cc
48 | Social networks: http://www.fb.com/blynkapp
49 | http://twitter.com/blynk_app
50 | =====================================================================================================================
51 | """
52 |
53 | import blynklib
54 | from datetime import datetime
55 |
56 | BLYNK_AUTH = 'YourAuthToken'
57 | blynk = blynklib.Blynk(BLYNK_AUTH)
58 |
59 |
60 | @blynk.handle_event("connect")
61 | def connect_handler():
62 | blynk.internal("rtc", "sync")
63 | print("RTC sync request was sent")
64 |
65 |
66 | @blynk.handle_event('internal_rtc')
67 | def rtc_handler(rtc_data_list):
68 | hr_rtc_value = datetime.utcfromtimestamp(int(rtc_data_list[0])).strftime('%Y-%m-%d %H:%M:%S')
69 | print('Raw RTC value from server: {}'.format(rtc_data_list[0]))
70 | print('Human readable RTC value: {}'.format(hr_rtc_value))
71 |
72 |
73 | ###########################################################
74 | # infinite loop that waits for event
75 | ###########################################################
76 | while True:
77 | blynk.run()
78 |
--------------------------------------------------------------------------------
/examples/11_ssl_socket.py:
--------------------------------------------------------------------------------
1 | """
2 | [SSL CONNECT/DISCONNECT EVENTS EXAMPLE] =================================================================
3 | NOTE!
4 | This example works correctly only fo cPython version of library (blynklib.py)
5 | For micropython present limitation that keyword arguments of wrap_socket may be not supported by certain ports
6 |
7 |
8 | Environment prepare:
9 | - define your auth token for current example and run it
10 |
11 |
12 | This started program after successful connect operation will call and execute "connect event handler"
13 | Within handler after short sleep delay blynk disconnect call will be performed that will trigger
14 | "disconnect event handler" execution.
15 |
16 | Schema:
17 | =====================================================================================================
18 | +-----------+ +--------------+
19 | | | | |
20 | | blynk lib | | blynk server |
21 | | | | virtual pin |
22 | | | | |
23 | +-----+-----+ +------+-------+
24 | | |
25 | | connect/authenticate request |
26 | +------------------------------------>+
27 | connect handler | |
28 | (user function) | connected successfully |
29 | +-----------<------------------------------------+
30 | | | |
31 | | | disconnect request |
32 | +--------->------------------------------------->+
33 | | |
34 | | |
35 | disconnect handler | |
36 | (user function) | disconnected successfully |
37 | +-----------<------------------------------------+
38 | | | |
39 | | | |
40 | +--------->+ |
41 | | reconnect request |
42 | | performed by lib automatically |
43 | +------------------------------------>+
44 | + +
45 |
46 |
47 | ====================================================================================================
48 | Additional info about blynk you can find by examining such resources:
49 |
50 | Downloads, docs, tutorials: https://blynk.io
51 | Sketch generator: http://examples.blynk.cc
52 | Blynk community: http://community.blynk.cc
53 | Social networks: http://www.fb.com/blynkapp
54 | http://twitter.com/blynk_app
55 | =====================================================================================================
56 | """
57 |
58 | import blynklib
59 | import time
60 | import logging
61 |
62 | # tune console logging
63 | _log = logging.getLogger('BlynkLog')
64 | logFormatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
65 | consoleHandler = logging.StreamHandler()
66 | consoleHandler.setFormatter(logFormatter)
67 | _log.addHandler(consoleHandler)
68 | _log.setLevel(logging.DEBUG)
69 |
70 | BLYNK_AUTH = 'YourAuthToken'
71 |
72 | blynk = blynklib.Blynk(BLYNK_AUTH, port=443, ssl_cert='../certificate/blynk-cloud.com.crt', log=_log.info)
73 |
74 | CONNECT_PRINT_MSG = '[CONNECT_EVENT]'
75 | DISCONNECT_PRINT_MSG = '[DISCONNECT_EVENT]'
76 |
77 |
78 | @blynk.handle_event("connect")
79 | def connect_handler():
80 | print(CONNECT_PRINT_MSG)
81 | print('Sleeping 4 sec in SSL connect handler...')
82 | time.sleep(4)
83 | blynk.disconnect()
84 |
85 |
86 | @blynk.handle_event("disconnect")
87 | def disconnect_handler():
88 | print(DISCONNECT_PRINT_MSG)
89 | print('Sleeping 3 sec in SSL disconnect handler...')
90 | time.sleep(5)
91 |
92 |
93 | ###########################################################
94 | # infinite loop that waits for event
95 | ###########################################################
96 | while True:
97 | blynk.run()
98 |
--------------------------------------------------------------------------------
/examples/12_app_connect_disconnect.py:
--------------------------------------------------------------------------------
1 | """
2 | [APP CONNECT DISCONNECT EVENTS EXAMPLE] ============================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - in Project Settings enable flag "Notify devices when APP connected"
7 | - define your auth token for current example and run it
8 | - Run the App (green triangle in the upper right corner).
9 |
10 | This started program will call handlers and print messages for APP_CONNECT or APP_DISCONNECT events.
11 |
12 | Schema:
13 | ====================================================================================================
14 | +-----------+ +--------------+ +--------------+
15 | | | | | | |
16 | | blynk lib | | blynk server | | blynk app |
17 | | | | virtual pin | | |
18 | | | | | | |
19 | +-----+-----+ +------+-------+ +-------+------+
20 | | | app connected or disconnected |
21 | | | from server |
22 | | |
23 | event handler | app connect/disconnect event +<-----------------------------------+
24 | (user function) | | |
25 | +------------<-----------------------------------+ |
26 | | | | |
27 | | | | |
28 | +--------->+ | |
29 | | | |
30 | | | |
31 | | | |
32 | | | |
33 | | | |
34 | | | |
35 | | | |
36 | | | |
37 | + + +
38 | ====================================================================================================
39 | Additional blynk info you can find by examining such resources:
40 |
41 | Downloads, docs, tutorials: https://blynk.io
42 | Sketch generator: http://examples.blynk.cc
43 | Blynk community: http://community.blynk.cc
44 | Social networks: http://www.fb.com/blynkapp
45 | http://twitter.com/blynk_app
46 | ====================================================================================================
47 | """
48 |
49 | import blynklib
50 |
51 | BLYNK_AUTH = 'YourAuthToken'
52 |
53 | # initialize Blynk
54 | blynk = blynklib.Blynk(BLYNK_AUTH)
55 |
56 | APP_CONNECT_PRINT_MSG = '[APP_CONNECT_EVENT]'
57 | APP_DISCONNECT_PRINT_MSG = '[APP_DISCONNECT_EVENT]'
58 |
59 |
60 | @blynk.handle_event('internal_acon')
61 | def app_connect_handler(*args):
62 | print(APP_CONNECT_PRINT_MSG)
63 |
64 |
65 | @blynk.handle_event('internal_adis')
66 | def app_disconnect_handler(*args):
67 | print(APP_DISCONNECT_PRINT_MSG)
68 |
69 |
70 | ###########################################################
71 | # infinite loop that waits for event
72 | ###########################################################
73 | while True:
74 | blynk.run()
75 |
--------------------------------------------------------------------------------
/examples/esp32/01_touch_button.py:
--------------------------------------------------------------------------------
1 | """
2 | [TOUCH BUTTON (TTP223B sensors) ESP32 TTGO T8 V1.7] =================================================================
3 |
4 | ESP32 pins schema:
5 | https://images-na.ssl-images-amazon.com/images/I/81%2Bjpo9-D8L._SX522_.jpg
6 |
7 | TTP223B sensor:
8 | - connect VCC sensor line to "+3.3v" board pin
9 | - connect GND sensor line to "ground" board pin
10 | - connect DATA sensor line to board GPIO2
11 |
12 | Environment prepare:
13 | In your Blynk App project:
14 | - add "Value Display" widget,
15 | - bind it to Virtual Pin V10,
16 | - set the read frequency to 5 second.
17 | - Run the App (green triangle in the upper right corner).
18 | - define SSID and WiFi password that will be used by ESP32 board
19 | - optionally change HW GPIO pin that will be used by touch button data line
20 | - define your auth token for current example and run it
21 |
22 | This started program will create system IRQ with callback for "button touched" event.
23 | Callback will store touch attempt number and touch time.
24 | Current program will periodically call and execute event handler "read_virtual_pin_handler".
25 | Handler reads stored last touch num and touch time values and by calling virtual_write
26 | operation updates widget value. In app you can see touch event updated info. Ex "#10 touch at 604705274".
27 | =====================================================================================================================
28 | Additional info about blynk you can find by examining such resources:
29 |
30 | Downloads, docs, tutorials: https://blynk.io
31 | Sketch generator: http://examples.blynk.cc
32 | Blynk community: http://community.blynk.cc
33 | Social networks: http://www.fb.com/blynkapp
34 | http://twitter.com/blynk_app
35 | =====================================================================================================================
36 | """
37 | import blynklib_mp as blynklib
38 | import network
39 | import utime as time
40 | from machine import Pin
41 |
42 |
43 | class Touch:
44 | num = 0
45 | time = 0
46 |
47 |
48 | def callback(pin):
49 | print('Touch event on {}'.format(pin))
50 | Touch.num += 1
51 | Touch.time = time.time()
52 |
53 |
54 | WIFI_SSID = 'YourWifiSSID'
55 | WIFI_PASS = 'YourWifiPassword'
56 | BLYNK_AUTH = 'YourAuthToken'
57 | GPIO_PIN = 2
58 |
59 | print("Connecting to WiFi network '{}'".format(WIFI_SSID))
60 | wifi = network.WLAN(network.STA_IF)
61 | wifi.active(True)
62 | wifi.connect(WIFI_SSID, WIFI_PASS)
63 | while not wifi.isconnected():
64 | time.sleep(1)
65 | print('WiFi connect retry ...')
66 | print('WiFi IP:', wifi.ifconfig()[0])
67 |
68 | print("Connecting to Blynk server...")
69 | blynk = blynklib.Blynk(BLYNK_AUTH)
70 |
71 | hw_pin = Pin(GPIO_PIN, Pin.IN)
72 | hw_pin.irq(trigger=Pin.IRQ_RISING, handler=callback)
73 |
74 |
75 | @blynk.handle_event('read V10')
76 | def read_virtual_pin_handler(vpin):
77 | print('Read event on vpin {}'.format(vpin))
78 | blynk.virtual_write(vpin, "#{} touch at {} ".format(Touch.num, Touch.time))
79 |
80 |
81 | while True:
82 | blynk.run()
83 |
--------------------------------------------------------------------------------
/examples/esp32/02_terminal_cli.py:
--------------------------------------------------------------------------------
1 | """
2 | [TERMINAL WIDGET ESP32 EXAMPLE] =====================================================================================
3 |
4 | Environment prepare:
5 | In your Blynk App project:
6 | - add "Terminal" widget,
7 | - bind it to Virtual Pin V2,
8 | - add input line option in widget settings
9 | - Run the App (green triangle in the upper right corner).
10 | - define your auth token for current example
11 | - define SSID and WiFi password that will be used by ESP32 board
12 | - run current example
13 |
14 |
15 | This started program will call and execute event handler "write_virtual_pin_handler" if new
16 | event comes from terminal app widget.
17 | In App Terminal widget you can type commands.
18 | 'help' - info about available commnds
19 | 'logo' - prints blynk library ascii logo
20 | 'version' - prints blynk library version
21 | 'sysinfo' - prints board system info
22 | 'ls' - list target board dir. Example: 'ls /lib'.
23 | root dir will be listed if no arguments provided
24 |
25 | For any other terminal inputs will be printed error info that provided command is not supported.
26 | =====================================================================================================================
27 | Additional info about blynk you can find by examining such resources:
28 |
29 | Downloads, docs, tutorials: https://blynk.io
30 | Sketch generator: http://examples.blynk.cc
31 | Blynk community: http://community.blynk.cc
32 | Social networks: http://www.fb.com/blynkapp
33 | http://twitter.com/blynk_app
34 | =====================================================================================================================
35 | """
36 | import blynklib_mp as blynklib
37 | import network
38 | import uos
39 | import utime as time
40 |
41 | WIFI_SSID = 'YourWifiSSID'
42 | WIFI_PASS = 'YourWifiPassword'
43 | BLYNK_AUTH = 'YourAuthToken'
44 |
45 | print("Connecting to WiFi network '{}'".format(WIFI_SSID))
46 | wifi = network.WLAN(network.STA_IF)
47 | wifi.active(True)
48 | wifi.connect(WIFI_SSID, WIFI_PASS)
49 | while not wifi.isconnected():
50 | time.sleep(1)
51 | print('WiFi connect retry ...')
52 | print('WiFi IP:', wifi.ifconfig()[0])
53 |
54 | print("Connecting to Blynk server...")
55 | blynk = blynklib.Blynk(BLYNK_AUTH)
56 |
57 | CMD_LIST = ['logo', 'version', 'sysinfo', 'ls']
58 |
59 |
60 | @blynk.handle_event('write V2')
61 | def write_handler(pin, values):
62 | if values:
63 | in_args = values[0].split(' ')
64 | cmd = in_args[0]
65 | cmd_args = in_args[1:]
66 |
67 | if cmd == 'help':
68 | output = ' '.join(CMD_LIST)
69 | elif cmd == CMD_LIST[0]:
70 | output = blynklib.LOGO
71 | elif cmd == CMD_LIST[1]:
72 | output = blynklib.__version__
73 | elif cmd == CMD_LIST[2]:
74 | output = uos.uname()
75 | elif cmd == CMD_LIST[3]:
76 | arg = cmd_args[0] if cmd_args else ''
77 | output = uos.listdir(arg)
78 | else:
79 | output = "[ERR]: Not supported command '{}'".format(values[0])
80 |
81 | blynk.virtual_write(pin, output)
82 | blynk.virtual_write(pin, '\n')
83 |
84 |
85 | while True:
86 | blynk.run()
87 |
--------------------------------------------------------------------------------
/examples/esp32/03_temperature_humidity_dht22.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | [TEMPERATURE/HUMIDITY SENSOR (DHT22) ESP32 TTGO T8 V1.7] ============================================================
4 |
5 | ESP32 pins schema:
6 | https://images-na.ssl-images-amazon.com/images/I/81%2Bjpo9-D8L._SX522_.jpg
7 |
8 | DHT22 sensor:
9 | - connect VCC sensor line to "+5" board pin
10 | - connect GND sensor line to "ground" board pin
11 | - connect DATA sensor line to board GPIO 4
12 |
13 | DHT22 datasheet that can be helpful:
14 | https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf
15 |
16 | Environment prepare:
17 | In your Blynk App project:
18 | - add "Gauge" widget,
19 | - bind it to Virtual Pin V3
20 | - set name "Temperature"
21 | - set label /pin.##/°C
22 | - set update time=15 sec and assign 0-100 values range to it
23 |
24 | - add "Gauge" widget,
25 | - bind it to Virtual Pin V4
26 | - set name "Humidity"
27 | - set label /pin.##/ %
28 | - set update time=15 sec and assign 0-100 values range to it
29 |
30 |
31 | - Run the App (green triangle in the upper right corner).
32 | - define SSID and WiFi password that will be used by ESP32 board
33 | - optionally change HW GPIO pin that will be used by touch button data line
34 | - define your auth token for current example and run it
35 |
36 | This started program will periodically call and execute event handler "read_virtual_pin_handler".
37 | that will try to get data from sensor and write them to related virtual pins.
38 | Within App widget values will be updated each 15 sec.
39 | If during cycle there was error in get data operation - widget colors will be changed to grey (aka disabled state)
40 | and restored on next successful read sensor data operation.
41 | =====================================================================================================================
42 | Additional info about blynk you can find by examining such resources:
43 |
44 | Downloads, docs, tutorials: https://blynk.io
45 | Sketch generator: http://examples.blynk.cc
46 | Blynk community: http://community.blynk.cc
47 | Social networks: http://www.fb.com/blynkapp
48 | http://twitter.com/blynk_app
49 | =====================================================================================================================
50 | """
51 | import blynklib_mp as blynklib
52 | import network
53 | import utime as time
54 | from machine import Pin
55 |
56 | # DHT driver already included into Micropython software as core module
57 | # so we just import it
58 | import dht
59 |
60 | WIFI_SSID = 'YourWifiSSID'
61 | WIFI_PASS = 'YourWifiPassword'
62 | BLYNK_AUTH = 'YourAuthToken'
63 | GPIO_DHT22_PIN = 4
64 |
65 | print("Connecting to WiFi network '{}'".format(WIFI_SSID))
66 | wifi = network.WLAN(network.STA_IF)
67 | wifi.active(True)
68 | wifi.connect(WIFI_SSID, WIFI_PASS)
69 | while not wifi.isconnected():
70 | time.sleep(1)
71 | print('WiFi connect retry ...')
72 | print('WiFi IP:', wifi.ifconfig()[0])
73 |
74 | print("Connecting to Blynk server...")
75 | blynk = blynklib.Blynk(BLYNK_AUTH)
76 |
77 | T_COLOR = '#f5b041'
78 | H_COLOR = '#85c1e9'
79 | ERR_COLOR = '#444444'
80 |
81 | T_VPIN = 3
82 | H_VPIN = 4
83 |
84 | dht22 = dht.DHT22(Pin(4, Pin.IN, Pin.PULL_UP))
85 |
86 |
87 | @blynk.handle_event('read V{}'.format(T_VPIN))
88 | def read_handler(vpin):
89 | temperature = 0.0
90 | humidity = 0.0
91 |
92 | # read sensor data
93 | try:
94 | dht22.measure()
95 | temperature = dht22.temperature()
96 | humidity = dht22.humidity()
97 | except OSError as o_err:
98 | print("Unable to get DHT22 sensor data: '{}'".format(o_err))
99 |
100 | # change widget values and colors according read results
101 | if temperature != 0.0 and humidity != 0.0:
102 | blynk.set_property(T_VPIN, 'color', T_COLOR)
103 | blynk.set_property(H_VPIN, 'color', H_COLOR)
104 | blynk.virtual_write(T_VPIN, temperature)
105 | blynk.virtual_write(H_VPIN, humidity)
106 | else:
107 | # show widgets aka 'disabled' that mean we had errors during read sensor operation
108 | blynk.set_property(T_VPIN, 'color', ERR_COLOR)
109 | blynk.set_property(H_VPIN, 'color', ERR_COLOR)
110 |
111 |
112 | while True:
113 | blynk.run()
114 |
--------------------------------------------------------------------------------
/examples/esp32/README.md:
--------------------------------------------------------------------------------
1 | # [ESP32 Micropython][esp32]
2 |
3 | ![esp32][esp32-banner]
4 | ## Board preparation
5 |
6 | - download latest micropython [firmware][micropython-download] for your board
7 | - on your host system install python3
8 | - install **[esptool][micropython-esptool]**, **[rshell][micropython-rshell]**, **[ampy][micropython-ampy]** on your host to communicate with esp32 board
9 | ```bash
10 | # Example on Linux
11 | sudo pip3 install esptool
12 | sudo pip3 install rshell
13 | sudo pip3 install adafruit-ampy
14 | ```
15 |
16 | - connect board via USB. Run command:
17 | ```bash
18 | dmesg | grep tty
19 | ```
20 | that will help to find ttyUSB connection port.This port will be used later for all communication operations
21 |
22 | - check board flash status. (In this example and below we assume that port=ttyUSB0)
23 | ```bash
24 | esptool.py --port /dev/ttyUSB0 flash_id
25 | ```
26 |
27 | - erase board flash before new firmware uploading
28 | ```bash
29 | esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
30 | ```
31 |
32 | - burn new firmware
33 | ```bash
34 | esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 [your esp32 firmware .bin]
35 | ```
36 |
37 | ## Board CLI
38 |
39 | - For board CLI access [rshell][micropython-rshell] can be used:
40 | ```bash
41 | rshell --buffer-size=30 -p /dev/ttyUSB0
42 | ```
43 | after board prompt appears ">" you will have access to some board commands:
44 | ```text
45 | args cat connect echo exit filetype ls repl rsync
46 | boards cd cp edit filesize help mkdir rm shell
47 | ```
48 | - **[repl][micropython-repl]** command will start micropython interactive shell.
49 |
50 | Also this shell can be used for board soft reboots(Ctrl+D).
51 |
52 | Hard reboots can be done by board "RST" button.
53 |
54 |
55 | ## Board files/directories operations
56 |
57 | - **[ampy][micropython-ampy]** utility can be used for storing/deleting files,
58 | directories creation/removing and scripts run
59 | ```bash
60 | export AMPY_PORT=/dev/ttyUSB0
61 | ampy mkdir /lib
62 | ampy put blynklib_mp.py /lib/blynklib_mp.py
63 | ampy put test.py test.py
64 | ampy run test.py
65 | ```
66 |
67 |
68 | ## Micropython libraries compiltation
69 |
70 | Micropython provides ability to compile source code into **.mpy** frozen module file.
71 | Main advantage of this that **.mpy** files will consume less RAM compared
72 | to raw Python .py source files
73 |
74 | For **.mpy** file compilation you need:
75 | - get **[mpy-cross][micropython-mpy-cross]** tool
76 | ```bash
77 | git clone https://github.com/micropython/micropython.git
78 | cd micropython/mpy-cross
79 | make
80 | ```
81 | - optionally get heapsize of your board via **[repl][micropython-repl]**.
82 | ```text
83 | >>> import gc
84 | >>> gc.collect()
85 | >>> gc.mem_free()
86 | 2812256
87 | ```
88 | - compile source code and get .mpy file
89 | ```bash
90 | ./mpy-cross -X heapsize=2812256 blynklib_mp.py
91 | ```
92 | - .mpy files in the same manner can be placed to board libs with **[ampy][micropython-ampy]**
93 | as usual .py file
94 | ```bash
95 | ampy put blynklib_mp.mpy /lib/blynklib_mp.mpy
96 | ```
97 | and then imported within user scripts as usual .py lib
98 | ```python
99 | # start of user script
100 | import blynklib_mp
101 | ```
102 |
103 | ## Wifi Connection
104 | Micropython allows to use core ***network*** module for WiFi connection setup.
105 |
106 | In script just place:
107 | ```python
108 | import network
109 |
110 | WIFI_SSID = 'YourWifiSSID'
111 | WIFI_PASS = 'YourWifiPassword'
112 |
113 | wifi = network.WLAN(network.STA_IF)
114 | wifi.active(True)
115 | wifi.connect(WIFI_SSID, WIFI_PASS)
116 |
117 | # check if board connected
118 | connect_status = wifi.isconnected()
119 |
120 | ```
121 |
122 |
123 | [esp32]: http://esp32.net
124 | [esp32-banner]: https://i.ytimg.com/vi/30f1n9h3aSc/maxresdefault.jpg
125 | [micropython-download]: http://micropython.org/download#esp32
126 | [micropython-repl]: https://docs.micropython.org/en/latest/esp8266/tutorial/repl.html
127 | [micropython-ampy]: https://github.com/pycampers/ampy
128 | [micropython-rshell]: https://github.com/dhylands/rshell
129 | [micropython-esptool]: https://github.com/espressif/esptool
130 | [micropython-mpy-cross]: https://pypi.org/project/mpy-cross/
--------------------------------------------------------------------------------
/examples/esp8266/01_potentiometer.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | [Slide Potentiometer NodeMcu ESP8266] ===============================================================================
4 |
5 | ESP8266 pinout:
6 | https://i.imgur.com/HgVTxCh.png
7 |
8 | Slide Potentiometer:
9 | - connect VCC sensor line to "+3.3v" board pin
10 | - connect GND sensor line to "ground" board pin
11 | - connect DATA sensor line to board A0 pib (ADC - analog to digital conversion on dedicated pin)
12 |
13 | Environment prepare:
14 | In your Blynk App project:
15 | - add "Gauge" widget,
16 | - bind it to Virtual Pin V1
17 | - set name "Potentiometer"
18 | - set label /pin.##/
19 | - set update time=1 sec and assign 0-1024 values range to it
20 |
21 |
22 | - Run the App (green triangle in the upper right corner).
23 | - define SSID and WiFi password that will be used by ESP32 board
24 | - define your auth token for current example and run it
25 |
26 | This started program will periodically call and execute event handler "read_virtual_pin_handler".
27 | that will try to get data from potentiometer and write it to related virtual pin.
28 | Within App widget gauge value will be updated each 1 sec.
29 | =====================================================================================================================
30 | Additional info about blynk you can find by examining such resources:
31 |
32 | Downloads, docs, tutorials: http://www.blynk.cc
33 | Sketch generator: http://examples.blynk.cc
34 | Blynk community: http://community.blynk.cc
35 | Social networks: http://www.fb.com/blynkapp
36 | http://twitter.com/blynk_app
37 | =====================================================================================================================
38 | """
39 | import blynklib_mp as blynklib
40 | import network
41 | import utime as time
42 | import machine
43 |
44 | WIFI_SSID = 'YourWifiSSID'
45 | WIFI_PASS = 'YourWifiPassword'
46 | BLYNK_AUTH = 'YourAuthToken'
47 |
48 | print("Connecting to WiFi network '{}'".format(WIFI_SSID))
49 | wifi = network.WLAN(network.STA_IF)
50 | wifi.active(True)
51 | wifi.connect(WIFI_SSID, WIFI_PASS)
52 | while not wifi.isconnected():
53 | time.sleep(1)
54 | print('WiFi connect retry ...')
55 | print('WiFi IP:', wifi.ifconfig()[0])
56 |
57 | print("Connecting to Blynk server...")
58 | blynk = blynklib.Blynk(BLYNK_AUTH)
59 | adc = machine.ADC(0)
60 |
61 |
62 | @blynk.handle_event('read V1')
63 | def read_handler(vpin):
64 | p_value = adc.read()
65 | print('Current potentiometer value={}'.format(p_value))
66 | blynk.virtual_write(vpin, p_value)
67 |
68 |
69 | while True:
70 | blynk.run()
71 |
--------------------------------------------------------------------------------
/examples/esp8266/README.md:
--------------------------------------------------------------------------------
1 | # [ESP8266 Micropython][esp8266]
2 |
3 | ![esp8266][esp8266-banner]
4 | ## Board firmware installation
5 |
6 | - download latest micropython [esp8266 firmware][micropython-download] for your board
7 | - on your host system install python3
8 | - install **[esptool][micropython-esptool]**, **[rshell][micropython-rshell]**, **[ampy][micropython-ampy]** on your host to communicate with esp32 board
9 | ```bash
10 | # Example on Linux
11 | sudo pip3 install esptool
12 | sudo pip3 install rshell
13 | sudo pip3 install adafruit-ampy
14 | ```
15 |
16 | - connect board via USB. Run command:
17 | ```bash
18 | dmesg | grep tty
19 | ```
20 | that will help to find ttyUSB connection port.This port will be used later for all communication operations
21 |
22 | - check board flash status. (In this example and below we assume that port=ttyUSB0)
23 | ```bash
24 | esptool.py --port /dev/ttyUSB0 flash_id
25 | ```
26 |
27 | - erase board flash before new firmware uploading
28 | ```bash
29 | esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
30 | ```
31 |
32 | - burn new firmware
33 | ```bash
34 | esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 [your esp32 firmware .bin]
35 | ```
36 |
37 | ## Board CLI
38 |
39 | - For board CLI access [rshell][micropython-rshell] can be used:
40 | ```bash
41 | rshell --buffer-size=30 -p /dev/ttyUSB0
42 | ```
43 | after board prompt appears ">" you will have access to some board commands:
44 | ```text
45 | args cat connect echo exit filetype ls repl rsync
46 | boards cd cp edit filesize help mkdir rm shell
47 | ```
48 | - **[repl][micropython-repl]** command will start micropython interactive shell.
49 |
50 | Also this shell can be used for board soft reboots(Ctrl+D).
51 |
52 | Hard reboots can be done by board "RST" button.
53 |
54 |
55 | ## Board files/directories operations
56 |
57 | - **[ampy][micropython-ampy]** utility can be used for storing/deleting files,
58 | directories creation/removing and scripts run
59 | ```bash
60 | export AMPY_PORT=/dev/ttyUSB0
61 | ampy mkdir /lib
62 | ampy put blynklib_mp.py /lib/blynklib_mp.py
63 | ampy put test.py test.py
64 | ampy run test.py
65 | ```
66 |
67 |
68 | ## Libraries importing under ESP8266 Micropython
69 |
70 | The firmware including the MicroPython subsystem is stored in the onboard flash.
71 | The remaining capacity is available for use. For reasons connected with the physical architecture
72 | of the flash memory part of this capacity may be inaccessible as a filesystem. In such cases this space
73 | may be employed by incorporating user modules into a firmware build which is then flashed to the device.
74 |
75 | There are two ways to achieve this:
76 | - frozen modules
77 | - frozen bytecode.
78 |
79 |
80 |
81 | ### Frozen module inside firmware
82 | Frozen modules store the Python source with the firmware.
83 |
84 | For custom esp8266 firmware build creation:
85 | - install docker to your host system. Steps how to do it under different OS described [here][docker-install]
86 | - clone with git esp8266 docker repository. Virtual environment will be needed for firmware build operation.
87 | ```bash
88 | git clone https://github.com/enqack/docker-esp8266-micropython.git
89 | cd ./docker-esp8266-micropython
90 | ```
91 | - place your library module to **docker-esp8266-micropython** root
92 | - modify Dockerfile. You need place your library module to esp8266 frozen modules directory.
93 | Thus **Copy** instruction in Dockerfile should be placed after **'RUN apt-get update'** and before **'USER micropython'**
94 | ```text
95 | RUN apt-get update ...
96 | ...
97 | COPY blynklib_mp.py /micropython/ports/esp8266/modules/blynklib_mp.py
98 | USER micropython
99 | ...
100 | ```
101 | - follow **[this][esp8266-build-docker]** instructions to build and copy custom esp8266 firmware.
102 |
103 | Build process can take some time ~ 15-40 minutes.
104 |
105 | - after firmware created and copied locally - you can try to burn it with **esptool** to your ESP8266 board.
106 | - connect to board CLI with **rshell** and test **blynklib_mp** availability within **repl**
107 | ```python
108 | import blynklib_mp
109 | print(blynklib_mp.LOGO)
110 | ```
111 |
112 |
113 | ### Frozen bytecode
114 | Frozen bytecode approach uses the cross compiler to convert the source to bytecode which is then stored with the firmware.
115 |
116 | Examine [this document][blynk-esp32-readme] to get more details how to compile *.py files into *.mpy bytecode
117 |
118 | After *.mpy files can be placed to **/lib** directory of esp8266 board with **ampy** tool. Libraries *.mpy can be simply imported
119 | in the same manner as standard *.py library
120 | ```python
121 | import blynklib_mp
122 | ```
123 |
124 | ***Note!!*** During custom firmware creation your libraries will be converted and adopted to esp8266 environment
125 | automatically. So you can create custom build and then just copy *.mpy files from docker system to local
126 | ```bash
127 | docker cp micropython:/micropython/ports/esp8266/build/frozen_mpy/blynklib_mp.mpy blynklib_mp.mpy
128 | ```
129 |
130 |
131 | ## Wifi Connection
132 | Micropython allows to use core ***network*** module for WiFi connection setup.
133 |
134 | In script just place:
135 | ```python
136 | import network
137 |
138 | WIFI_SSID = 'YourWifiSSID'
139 | WIFI_PASS = 'YourWifiPassword'
140 |
141 | wifi = network.WLAN(network.STA_IF)
142 | wifi.active(True)
143 | wifi.connect(WIFI_SSID, WIFI_PASS)
144 |
145 | # check if board connected
146 | connect_status = wifi.isconnected()
147 | ```
148 |
149 |
150 | [esp8266]: https://en.wikipedia.org/wiki/ESP8266
151 | [esp8266-banner]: http://arduino.ua/products_pictures/large_AOC400-1.jpg
152 | [micropython-download]: http://micropython.org/download#esp8266
153 | [micropython-repl]: https://docs.micropython.org/en/latest/esp8266/tutorial/repl.html
154 | [micropython-ampy]: https://github.com/pycampers/ampy
155 | [micropython-rshell]: https://github.com/dhylands/rshell
156 | [micropython-esptool]: https://github.com/espressif/esptool
157 | [micropython-mpy-cross]: https://pypi.org/project/mpy-cross/
158 | [esp8266-build-docker]: https://github.com/enqack/docker-esp8266-micropython
159 | [docker-install]: https://docs.docker.com/install/linux/docker-ce/ubuntu/
160 | [blynk-esp32-readme]: https://github.com/blynkkk/lib-python/blob/master/examples/esp32/README.md
--------------------------------------------------------------------------------
/examples/raspberry/01_weather_station_pi3b.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | [WEATHER STATION EXAMPLE (DHT22; BMP180 sensors) PI3b+] =============================================================
4 |
5 | PI3b+ pins schema:
6 | https://www.theengineeringprojects.com/wp-content/uploads/2018/07/introduction-to-raspberry-pi-3-b-plus-2.png
7 |
8 | DHT22 sensor:
9 | - connect VCC sensor line to "+5v" board pin
10 | - connect GND sensor line to "ground" board pin
11 | - connect DATA sensor line to board GPIO17
12 | - pip install Adafruit-DHT
13 |
14 | DHT22 datasheet that can be helpful:
15 | https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf
16 |
17 |
18 | BMP180 sensor:
19 | - connect VIN sensor line to "+3.3v" board pin
20 | - connect GND sensor line to "ground" board pin
21 | - connect SCL sensor line to board GPIO3 (SCL)
22 | - connect SDA sensor line to board GPIO2 (SDA)
23 |
24 | - ensure that i2c-tools package installed in your system 'aptitude show i2c-tools'
25 | - if not installed run 'sudo apt-get install i2c-tools'
26 | - ensure that i2c interface was enabled in your system
27 | 'sudo raspi-config' -> Interfacing Options -> I2C enable -> Confirm -> then board reboot
28 | - run 'sudo i2cdetect -y 1' that will detect i2c devices.
29 | If sensor was connected correctly within output table you will see "77"
30 | - to install BPM python lib you will need get BMP180 archived project and install lib from local files:
31 | git clone https://github.com/adafruit/Adafruit_Python_BMP
32 | cd Adafruit_Python_BMP
33 | sudo python setup.py install
34 |
35 | BMP180 datasheet that can be helpful:
36 | https://arduino.ua/docs/BMP085_DataSheet_Rev.1.0_01July2008.pdf
37 |
38 |
39 | Environment prepare:
40 | In your Blynk App project:
41 | - add "Notification" widget
42 |
43 | - add "Gauge" widget,
44 | - bind it to Virtual Pin V7
45 | - set name "Temperature"
46 | - set label /pin.##/°C
47 | - set update time=10 sec and assign 0-100 values range to it
48 |
49 | - add "Gauge" widget,
50 | - bind it to Virtual Pin V8
51 | - set name "Humidity"
52 | - set label /pin.##/ %
53 | - set update time=10 sec and assign 0-100 values range to it
54 |
55 | - add "Gauge" widget,
56 | - bind it to Virtual Pin V9
57 | - set name "Pressure"
58 | - set label /pin/ Hg
59 | - set update time=10 sec and assign 0-800 values range to it
60 |
61 | - add "Gauge" widget,
62 | - bind it to Virtual Pin V10
63 | - set name "Altitude"
64 | - set label /pin.##/ m
65 | - set update time=10 sec and assign 0-1000 values range to it
66 |
67 | - Run the App (green triangle in the upper right corner).
68 | - define your auth token for current example
69 | - optionally change default critical temperature value to your own
70 | - run current example
71 |
72 | This started program will periodically call and execute event handler "read_virtual_pin_handler".
73 | that will try to get data from sensors and write them to related virtual pins.
74 | Within App widget values will be updated each 10 sec.
75 | If during cycle there was error in get data operation - widget colors will be changed to grey (aka disabled state)
76 | and restored on next successful read sensor data operation. Additionally if temperature will be less than
77 | critical value (default = 20°C) handler will send warning notification to on App.
78 |
79 | Schema for temperature parameter:
80 | =====================================================================================================================
81 | +-----------+ +--------------+ +--------------+
82 | | | | | | |
83 | | blynk lib | | blynk server | | blynk app |
84 | | | | virtual pin | | |
85 | | | | | | |
86 | +-----------+ +--------------+ +--------------+
87 | | | |
88 | | | |
89 | | | widget read frequency = 10 sec |
90 | | +<-----------------------------------+
91 | | | |
92 | | | |
93 | | | send virtual pin value to widget |
94 | | | |
95 | event handler | read event to hw from server +----------------------------------->+
96 | (user function) | | |
97 | +-----------<------------------------------------+ |
98 | | | | |
99 | | | write temperature value to pin | |
100 | +--------->------------------------------------->+ next widget read event |
101 | | optionally: | |
102 | | - set widget property +<-----------------------------------+
103 | | - send notification | |
104 | | | |
105 | + + +
106 | =====================================================================================================================
107 | Additional info about blynk you can find by examining such resources:
108 |
109 | Downloads, docs, tutorials: https://blynk.io
110 | Sketch generator: http://examples.blynk.cc
111 | Blynk community: http://community.blynk.cc
112 | Social networks: http://www.fb.com/blynkapp
113 | http://twitter.com/blynk_app
114 | =====================================================================================================================
115 | """
116 |
117 | import blynklib
118 | import Adafruit_DHT
119 | import Adafruit_BMP.BMP085 as BMP085
120 |
121 |
122 | class Counter:
123 | cycle = 0
124 |
125 |
126 | BLYNK_AUTH = 'YourAuthToken'
127 | blynk = blynklib.Blynk(BLYNK_AUTH, heartbeat=15, max_msg_buffer=512)
128 |
129 | T_CRI_VALUE = 20.0 # 20.0°C
130 | T_CRI_MSG = 'Low TEMP!!!'
131 | T_CRI_COLOR = '#c0392b'
132 |
133 | T_COLOR = '#f5b041'
134 | H_COLOR = '#85c1e9'
135 | P_COLOR = '#a2d9ce'
136 | A_COLOR = '#58d68d'
137 | ERR_COLOR = '#444444'
138 |
139 | T_VPIN = 7
140 | H_VPIN = 8
141 | P_VPIN = 9
142 | A_VPIN = 10
143 | GPIO_DHT22_PIN = 17
144 |
145 |
146 | @blynk.handle_event('read V{}'.format(T_VPIN))
147 | def read_handler(vpin):
148 | # DHT22
149 | dht22_sensor = Adafruit_DHT.DHT22 # possible sensor modifications .DHT11 .DHT22 .AM2302. Also DHT21 === DHT22
150 | humidity, temperature = Adafruit_DHT.read_retry(dht22_sensor, GPIO_DHT22_PIN, retries=5, delay_seconds=1)
151 | Counter.cycle += 1
152 | # check that values are not False (mean not None)
153 | if all([humidity, temperature]):
154 | print('temperature={} humidity={}'.format(temperature, humidity))
155 | if temperature <= T_CRI_VALUE:
156 | blynk.set_property(T_VPIN, 'color', T_CRI_COLOR)
157 | # send notifications not each time but once a minute (6*10 sec)
158 | if Counter.cycle % 6 == 0:
159 | blynk.notify(T_CRI_MSG)
160 | Counter.cycle = 0
161 | else:
162 | blynk.set_property(T_VPIN, 'color', T_COLOR)
163 | blynk.set_property(H_VPIN, 'color', H_COLOR)
164 | blynk.virtual_write(T_VPIN, temperature)
165 | blynk.virtual_write(H_VPIN, humidity)
166 | else:
167 | print('[ERROR] reading DHT22 sensor data')
168 | blynk.set_property(T_VPIN, 'color', ERR_COLOR) # show aka 'disabled' that mean we errors on data read
169 | blynk.set_property(H_VPIN, 'color', ERR_COLOR)
170 |
171 | # BMP180
172 | bmp180_sensor = BMP085.BMP085(busnum=1)
173 | pressure = bmp180_sensor.read_pressure()
174 | altitude = bmp180_sensor.read_altitude()
175 | # check that values are not False (mean not None)
176 | if all([pressure, altitude]):
177 | print('pressure={} altitude={}'.format(pressure, altitude))
178 | blynk.set_property(P_VPIN, 'color', P_COLOR)
179 | blynk.set_property(A_VPIN, 'color', A_COLOR)
180 | blynk.virtual_write(P_VPIN, pressure / 133.322) # mmHg 1mmHg = 133.322 Pa
181 | blynk.virtual_write(A_VPIN, altitude)
182 | else:
183 | print('[ERROR] reading BMP180 sensor data')
184 | blynk.set_property(P_VPIN, 'color', ERR_COLOR) # show aka 'disabled' that mean we errors on data read
185 | blynk.set_property(A_VPIN, 'color', ERR_COLOR)
186 |
187 |
188 | ###########################################################
189 | # infinite loop that waits for event
190 | ###########################################################
191 | while True:
192 | blynk.run()
193 |
--------------------------------------------------------------------------------
/examples/raspberry/README.md:
--------------------------------------------------------------------------------
1 | # [Raspberry Pi][raspberry]
2 | A small and affordable computer that you can use to learn programming
3 |
4 | ![Blynk Banner][raspberry-banner]
5 |
6 | ## Board preparation
7 |
8 | - Micro Sd card will be needed with capacity >= 8 Gb (for installation without GUI 4Gb card can be used)
9 | - Download latest **[raspbian os][raspbian]** (debian based os for raspberry devices)
10 | - Examine these instructions **[windows setup][install-windows]**, **[linux setup][install-linux]**,
11 | **[headless-setup][install-headless]**, **[remote vnc][install-vnc]**, **[wifi][install-wifi]**.
12 |
13 | - For GPIO interface communication **[wiring Pi][wiring-pi]** should be installed
14 | This will allow you to communicate with GPIO pins directly via board CLI.
15 |
16 | For example:
17 | ```bash
18 | # prints pin diagram appropriate to your Pi
19 | gpio readall
20 | ```
21 | - install ***rpi.gpio*** module to communicate with GPIO pins from Python scripts
22 | ```bash
23 | sudo apt-get update
24 | sudo apt-get -y install python-rpi.gpio
25 |
26 | # sudo apt-get -y install python3-rpi.gpio # for Python3
27 | ```
28 | ## Security
29 |
30 | Protect your device and to avoid situations when it can be used without your permission.
31 |
32 | Read this [guide][raspberry-security] to understand how to impove rasberry Pi security.
33 |
34 |
35 |
36 |
37 | [raspberry]: https://www.raspberrypi.org/
38 | [raspberry-banner]: https://www.raspberrypi.org/app/uploads/2018/03/770A5842-1612x1080.jpg
39 | [raspbian]: https://www.raspberrypi.org/downloads/raspbian/
40 | [install-windows]: https://howtoraspberrypi.com/create-raspbian-sd-card-raspberry-pi-windows/
41 | [install-headless]: https://howtoraspberrypi.com/how-to-raspberry-pi-headless-setup/
42 | [install-linux]: https://howtoraspberrypi.com/create-sd-card-raspberry-pi-command-line-linux/
43 | [install-vnc]:https://howtoraspberrypi.com/raspberry-pi-vnc/
44 | [install-wifi]: https://howtoraspberrypi.com/connect-wifi-raspberry-pi-3-others/
45 | [wiring-pi]: http://wiringpi.com/download-and-install/
46 | [raspberry-security]: https://www.raspberrypi.org/documentation/configuration/security.md
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [aliases]
2 | test=pytest
3 |
4 | [metadata]
5 | description-file = README.md
6 |
7 | [tool:pytest]
8 | addopts = --verbose
9 | python_files = test/*.py
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | with open("README.md", "r") as fh:
4 | long_description = fh.read()
5 |
6 | setup(
7 | name='blynklib',
8 | version='0.2.6',
9 | description='Blynk Python/Micropython library',
10 | long_description=long_description,
11 | long_description_content_type="text/markdown",
12 | url='https://github.com/blynkkk/lib-python',
13 | license='MIT',
14 | author='Anton Morozenko',
15 | author_email='antoha.ua@gmail.com',
16 | setup_requires=['pytest-runner', ],
17 | tests_require=['pytest', 'pytest-mock>=1.11.2', ],
18 | py_modules=['blynklib', 'blynktimer', 'blynklib_mp'],
19 | classifiers=[
20 | "Programming Language :: Python :: 2.7",
21 | "Programming Language :: Python :: 3",
22 | "License :: OSI Approved :: MIT License",
23 | "Operating System :: OS Independent",
24 | ],
25 | )
26 |
--------------------------------------------------------------------------------
/test/test_blynk_connection.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import print_function
3 | import time
4 | import pytest
5 | import socket
6 | from blynklib import Connection, BlynkError, RedirectError
7 |
8 |
9 | class TestBlynkConnection:
10 | @pytest.fixture
11 | def cb(self):
12 | connection = Connection('1234', log=print)
13 | yield connection
14 |
15 | def test_send(self, cb, mocker):
16 | cb._socket = socket.socket()
17 | mocker.patch('socket.socket.send', return_value=5)
18 | result = cb.send('1234')
19 | assert result == 5
20 |
21 | def test_send_ioerror(self, cb, mocker):
22 | cb._socket = socket.socket()
23 | mocker.patch('socket.socket.send', side_effect=IOError('IO'))
24 | result = cb.send('1234')
25 | assert result is None
26 |
27 | def test_send_oserror(self, cb, mocker):
28 | cb._socket = socket.socket()
29 | mocker.patch('socket.socket.send', side_effect=OSError('OS'))
30 | result = cb.send('1234')
31 | assert result is None
32 |
33 | def test_send_socket_timeout(self, cb, mocker):
34 | cb._socket = socket.socket()
35 | mocker.patch('socket.socket.send', side_effect=socket.timeout())
36 | result = cb.send('1234')
37 | assert result is None
38 |
39 | def test_send_error_retry_count(self, cb, mocker):
40 | cb._socket = socket.socket()
41 | mocker.patch('socket.socket.send', side_effect=OSError('OS'))
42 | mocker.spy(time, 'sleep')
43 | cb.send('1234')
44 | assert cb._socket.send.call_count == 3
45 |
46 | def test_receive(self, cb, mocker):
47 | cb._socket = socket.socket()
48 | mocker.patch('socket.socket.recv', return_value=b'12345')
49 | result = cb.receive(10, 1)
50 | assert result == b'12345'
51 |
52 | def test_receive_timeout(self, cb, mocker):
53 | cb._socket = socket.socket()
54 | mocker.patch('socket.socket.recv', side_effect=OSError('timed out'))
55 | result = cb.receive(10, 1)
56 | assert result == b''
57 |
58 | def test_receive_timeout_2(self, cb, mocker):
59 | cb._socket = socket.socket()
60 | mocker.patch('socket.socket.recv', side_effect=socket.timeout('timed out'))
61 | result = cb.receive(10, 1)
62 | assert result == b''
63 |
64 | def test_receive_eagain(self, cb, mocker):
65 | cb._socket = socket.socket()
66 | mocker.patch('socket.socket.recv', side_effect=IOError('[Errno 11]'))
67 | result = cb.receive(10, 1)
68 | assert result == b''
69 |
70 | def test_receive_etimeout(self, cb, mocker):
71 | cb._socket = socket.socket()
72 | mocker.patch('socket.socket.recv', side_effect=OSError('[Errno 60]'))
73 | result = cb.receive(10, 1)
74 | assert result == b''
75 |
76 | def test_receive_raise_other_oserror(self, cb, mocker):
77 | cb._socket = socket.socket()
78 | mocker.patch('socket.socket.recv', side_effect=OSError('[Errno 13]'))
79 | with pytest.raises(OSError) as os_err:
80 | cb.receive(10, 1)
81 | assert '[Errno 13]' in str(os_err.value)
82 |
83 | def test_is_server_alive_negative(self, cb):
84 | result = cb.is_server_alive()
85 | assert result is False
86 |
87 | def test_is_server_alive_positive_ping(self, cb, mocker):
88 | cb._last_rcv_time = int(time.time() * 1000)
89 | mocker.patch.object(cb, 'send', return_value=None)
90 | result = cb.is_server_alive()
91 | assert result is True
92 |
93 | def test_is_server_alive_positive_no_ping_1(self, cb):
94 | cb._last_rcv_time = int(time.time() * 1000)
95 | cb._last_ping_time = int(time.time() * 1000)
96 | result = cb.is_server_alive()
97 | assert result is True
98 |
99 | def test_is_server_alive_positive_no_ping_2(self, cb):
100 | cb._last_rcv_time = int(time.time() * 1000)
101 | cb._last_send_time = int(time.time() * 1000)
102 | result = cb.is_server_alive()
103 | assert result is True
104 |
105 | def test_get_socket(self, cb, mocker):
106 | mocker.patch('socket.socket')
107 | mocker.patch('socket.getaddrinfo')
108 | cb._get_socket()
109 | assert cb._state == cb.CONNECTING
110 |
111 | def test_get_socket_exception(self, cb, mocker):
112 | mocker.patch('socket.socket')
113 | mocker.patch('socket.getaddrinfo', side_effect=BlynkError('BE'))
114 | with pytest.raises(BlynkError) as b_err:
115 | cb._get_socket()
116 | assert 'Connection with the Blynk server failed: BE' in str(b_err.value)
117 |
118 | def test_authenticate(self, cb, mocker):
119 | mocker.patch.object(cb, 'send', return_value=None)
120 | mocker.patch.object(cb, 'receive', return_value=b'\x00\x00\x02\x00\xc8')
121 | cb._authenticate()
122 | assert cb._state == cb.AUTHENTICATED
123 |
124 | def test_authenticate_invalid_auth_token(self, cb, mocker):
125 | mocker.patch.object(cb, 'send', return_value=None)
126 | mocker.patch.object(cb, 'receive', return_value=b'\x00\x00\x02\x00\x09')
127 | with pytest.raises(BlynkError) as b_err:
128 | cb._authenticate()
129 | assert 'Invalid Auth Token' in str(b_err.value)
130 |
131 | def test_authenticate_redirect_message(self, cb, mocker):
132 | mocker.patch.object(cb, 'send', return_value=None)
133 | mocker.patch.object(cb, 'receive', return_value=b'\x29\x00\x02\x00\x11127.0.0.1\x004444')
134 | with pytest.raises(RedirectError) as r_err:
135 | cb._authenticate()
136 | # pytest exception wraps real exception - so we need access value field first
137 | assert '127.0.0.1' in r_err.value.server
138 | assert '4444' in r_err.value.port
139 |
140 | def test_authenticate_not_ok_status(self, cb, mocker):
141 | mocker.patch.object(cb, 'send', return_value=None)
142 | mocker.patch.object(cb, 'receive', return_value=b'\x00\x00\x02\x00\x19')
143 | with pytest.raises(BlynkError) as b_err:
144 | cb._authenticate()
145 | assert 'Auth stage failed. Status=25' in str(b_err.value)
146 |
147 | def test_authenticate_timeout(self, cb, mocker):
148 | mocker.patch.object(cb, 'send', return_value=None)
149 | mocker.patch.object(cb, 'receive', return_value=None)
150 | with pytest.raises(BlynkError) as b_err:
151 | cb._authenticate()
152 | assert 'Auth stage timeout' in str(b_err.value)
153 |
154 | def test_set_heartbeat_timeout(self, cb, mocker):
155 | mocker.patch.object(cb, 'send', return_value=None)
156 | mocker.patch.object(cb, 'receive', return_value=None)
157 | with pytest.raises(BlynkError) as b_err:
158 | cb._set_heartbeat()
159 | assert 'Heartbeat stage timeout' in str(b_err.value)
160 |
161 | def test_set_heartbeat_error_status(self, cb, mocker):
162 | mocker.patch.object(cb, 'send', return_value=None)
163 | mocker.patch.object(cb, 'receive', return_value=b'\x00\x00\x02\x00\x0e')
164 | with pytest.raises(BlynkError) as b_err:
165 | cb._set_heartbeat()
166 | assert 'Set heartbeat returned code=14' in str(b_err.value)
167 |
168 | def test_set_heartbeat_positive(self, cb, mocker):
169 | mocker.patch.object(cb, 'send', return_value=None)
170 | mocker.patch.object(cb, 'receive', return_value=b'\x00\x00\x02\x00\xc8')
171 | cb._set_heartbeat()
172 |
173 | def test_connected_false(self, cb):
174 | result = cb.connected()
175 | assert result is False
176 |
177 | def test_connected_true(self, cb):
178 | cb._state = cb.AUTHENTICATED
179 | result = cb.connected()
180 | assert result is True
181 |
--------------------------------------------------------------------------------
/test/test_blynk_main.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import print_function
3 | import socket
4 | import pytest
5 | import blynklib
6 |
7 |
8 | class TestBlynk:
9 | @pytest.fixture
10 | def bl(self):
11 | blynk = blynklib.Blynk('1234', log=print)
12 | yield blynk
13 |
14 | def test_connect(self, bl, mocker):
15 | mocker.patch.object(bl, 'connected', return_value=False)
16 | mocker.patch.object(bl, '_get_socket', return_value=None)
17 | mocker.patch.object(bl, '_authenticate', return_value=None)
18 | mocker.patch.object(bl, '_set_heartbeat', return_value=None)
19 | mocker.patch.object(bl, 'call_handler', return_value=None)
20 | mocker.patch.object(blynklib, 'ticks_ms', return_value=42)
21 | result = bl.connect()
22 | assert result is True
23 | assert bl._last_rcv_time == 42
24 |
25 | def test_connect_exception(self, bl, mocker):
26 | mocker.patch.object(bl, 'connected', return_value=False)
27 | mocker.patch.object(bl, '_get_socket', return_value=None)
28 | mocker.patch.object(bl, '_authenticate', side_effect=blynklib.BlynkError())
29 | mocker.patch.object(bl, 'disconnect', return_value=None)
30 | mocker.patch('time.sleep', return_value=None)
31 | mocker.spy(bl, 'disconnect')
32 | result = bl.connect(0.001)
33 | assert result is False
34 | assert bl.disconnect.call_count > 1
35 |
36 | def test_connect_redirect_exception(self, bl, mocker):
37 | mocker.patch.object(bl, 'connected', return_value=False)
38 | mocker.patch.object(bl, '_get_socket', return_value=None)
39 | mocker.patch.object(bl, '_authenticate', side_effect=blynklib.RedirectError('127.0.0.1', 4444))
40 | mocker.patch.object(bl, 'disconnect', return_value=None)
41 | mocker.patch('time.sleep', return_value=None)
42 | mocker.spy(bl, 'disconnect')
43 | result = bl.connect(0.001)
44 | assert result is False
45 | assert bl.disconnect.call_count > 1
46 | assert bl.server == '127.0.0.1'
47 | assert bl.port == 4444
48 |
49 | def test_connect_timeout(self, bl, mocker):
50 | bl._state = bl.CONNECTING
51 | mocker.patch.object(bl, 'connected', return_value=False)
52 | result = bl.connect(0.001)
53 | assert result is False
54 |
55 | def test_disconnect(self, bl, mocker):
56 | bl._socket = socket.socket()
57 | mocker.patch('time.sleep', return_value=None)
58 | bl.disconnect('123')
59 |
60 | def test_virtual_write(self, bl, mocker):
61 | mocker.patch.object(bl, 'send', return_value=10)
62 | result = bl.virtual_write(20, 'va1', 'val2')
63 | assert result == 10
64 |
65 | def test_virtual_sync(self, bl, mocker):
66 | mocker.patch.object(bl, 'send', return_value=20)
67 | result = bl.virtual_sync(20, 22)
68 | assert result == 20
69 |
70 | def test_email(self, bl, mocker):
71 | mocker.patch.object(bl, 'send', return_value=30)
72 | result = bl.email('1', '2', '3')
73 | assert result == 30
74 |
75 | def test_tweet(self, bl, mocker):
76 | mocker.patch.object(bl, 'send', return_value=40)
77 | result = bl.tweet('123')
78 | assert result == 40
79 |
80 | def test_notify(self, bl, mocker):
81 | mocker.patch.object(bl, 'send', return_value=50)
82 | result = bl.notify('123')
83 | assert result == 50
84 |
85 | def test_set_property(self, bl, mocker):
86 | mocker.patch.object(bl, 'send', return_value=60)
87 | result = bl.set_property(1, '2', '3')
88 | assert result == 60
89 |
90 | def test_internal(self, bl, mocker):
91 | mocker.patch.object(bl, 'send', return_value=70)
92 | result = bl.internal('rtc', 'sync')
93 | assert result == 70
94 |
95 | def test_hadle_event(self, bl):
96 | bl._events = {}
97 |
98 | @bl.handle_event('connect')
99 | def connect_handler():
100 | pass
101 |
102 | @bl.handle_event('disconnect')
103 | def disconnect_handler():
104 | pass
105 |
106 | assert 'connect' in bl._events.keys()
107 | assert 'disconnect' in bl._events.keys()
108 |
109 | def test_read_wildcard_event(self, bl):
110 | bl._events = {}
111 |
112 | @bl.handle_event('read v*')
113 | def read_pin_handler():
114 | pass
115 |
116 | assert 'read v10' in bl._events.keys()
117 | assert len(bl._events.keys()) == bl.VPIN_MAX_NUM + 1
118 |
119 | def test_write_wildcard_event(self, bl):
120 | bl._events = {}
121 |
122 | @bl.handle_event('write v*')
123 | def write_pin_handler():
124 | pass
125 |
126 | assert 'write v5' in bl._events.keys()
127 | assert len(bl._events.keys()) == bl.VPIN_MAX_NUM + 1
128 |
129 | def test_call_handler(self, bl):
130 | bl._events = {}
131 |
132 | @bl.handle_event('write v2')
133 | def write_pin_handler(arg1, kwarg1=None):
134 | bl._state = 'TEST{}{}'.format(arg1, kwarg1)
135 |
136 | bl.call_handler('write v2', 12, kwarg1='34')
137 | assert bl._state == 'TEST1234'
138 |
139 | def test_process_rsp(self, bl, mocker):
140 | mocker.spy(bl, 'log')
141 | bl.process(bl.MSG_RSP, 100, 200, [])
142 | assert bl.log.call_count == 1
143 |
144 | def test_process_ping(self, bl, mocker):
145 | mocker.patch.object(bl, 'send', return_value=None)
146 | mocker.spy(bl, 'send')
147 | bl.process(bl.MSG_PING, 100, 200, [])
148 | assert bl.send.call_count == 1
149 |
150 | def test_process_internal(self, bl, mocker):
151 | bl._events = {}
152 |
153 | @bl.handle_event('internal_xyz')
154 | def internal_handler(*args):
155 | bl._status = 'INTERNAL TEST {}'.format(*args)
156 |
157 | mocker.patch.object(bl, 'send', return_value=None)
158 | bl.process(bl.MSG_INTERNAL, 100, 20, ['xyz', 'add', 2])
159 | assert bl._status == "INTERNAL TEST ['add', 2]"
160 |
161 | def test_process_write(self, bl, mocker):
162 | bl._events = {}
163 |
164 | @bl.handle_event('write V4')
165 | def write_handler(pin, *values):
166 | bl._status = 'WRITE TEST{}'.format(*values)
167 |
168 | mocker.patch.object(bl, 'send', return_value=None)
169 | bl.process(bl.MSG_HW, 100, 200, ['vw', 4, 1, 2])
170 | assert bl._status == 'WRITE TEST[1, 2]'
171 |
172 | def test_process_read(self, bl, mocker):
173 | bl._events = {}
174 |
175 | @bl.handle_event('read V7')
176 | def read_handler(pin):
177 | bl._status = 'READ TEST{}'.format(pin)
178 |
179 | mocker.patch.object(bl, 'send', return_value=None)
180 | bl.process(bl.MSG_HW, 100, 200, ['vr', 7])
181 | assert bl._status == 'READ TEST7'
182 |
--------------------------------------------------------------------------------
/test/test_blynk_protocol.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import sys
3 | import pytest
4 | from blynklib import Protocol, BlynkError
5 |
6 |
7 | class TestBlynkProtocol:
8 | @pytest.fixture
9 | def pb(self):
10 | protocol = Protocol()
11 | yield protocol
12 |
13 | def test_get_msg_id(self, pb):
14 | pb._msg_id = 4
15 | msg_id = pb._get_msg_id()
16 | assert msg_id == 5
17 |
18 | def test_get_msg_id_before_loop(self, pb):
19 | pb._msg_id = 0xFFFE
20 | msg_id = pb._get_msg_id()
21 | assert msg_id == 0xFFFF
22 |
23 | def test_get_msg_id_after_loop(self, pb):
24 | pb._msg_id = 0xFFFF
25 | msg_id = pb._get_msg_id()
26 | assert msg_id == 1
27 |
28 | def test_get_msg_id_defined(self, pb):
29 | pb._msg_id = 0xFFFF
30 | msg_id = pb._get_msg_id(msg_id=17)
31 | assert msg_id == 17
32 |
33 | def test_pack_msg(self, pb):
34 | msg_type = 20
35 | args = ['test', 1234, 745, 'abcde']
36 | result = pb._pack_msg(msg_type, *args)
37 | assert result == b'\x14\x00\x01\x00\x13test\x001234\x00745\x00abcde'
38 |
39 | def test_pack_msg_no_args(self, pb):
40 | msg_type = 15
41 | args = []
42 | result = pb._pack_msg(msg_type, *args)
43 | assert result == b'\x0f\x00\x01\x00\x00'
44 |
45 | def test_pack_msg_unicode(self, pb):
46 | if sys.version_info[0] == 2:
47 | pytest.skip('Python2 unicode compatibility issue')
48 |
49 | msg_type = 20
50 | args = ['ёж']
51 | result = pb._pack_msg(msg_type, *args)
52 | assert result == b'\x14\x00\x01\x00\x04\xd1\x91\xd0\xb6'
53 |
54 | def test_parse_response_msg_hw(self, pb):
55 | data = b'\x14\x00\x02\x00\x13test\x001234\x00745\x00abcde'
56 | msg_buffer = 1024
57 | result = pb.parse_response(data, msg_buffer)
58 | assert result == (20, 2, 19, [u'test', u'1234', u'745', u'abcde'])
59 |
60 | def test_parse_response_msg_id_0(self, pb):
61 | data = b'\x14\x00\x00\x00\x13test\x001234\x00745\x00abcde'
62 | msg_buffer = 100
63 | with pytest.raises(BlynkError) as b_err:
64 | pb.parse_response(data, msg_buffer)
65 | assert 'invalid msg_id == 0' == str(b_err.value)
66 |
67 | def test_parse_response_more_data_than_buffer(self, pb):
68 | data = b'\x14\x00\x02\x00\x13test\x001234\x00745\x00abcde'
69 | msg_buffer = 10
70 | with pytest.raises(BlynkError) as b_err:
71 | pb.parse_response(data, msg_buffer)
72 | assert 'Command too long' in str(b_err.value)
73 |
74 | def test_parse_response_msg_ping(self, pb):
75 | data = b'\x06\x00\x04\x00\x13test\x001234\x00745\x00abcde'
76 | msg_buffer = 100
77 | result = pb.parse_response(data, msg_buffer)
78 | assert result == (6, 4, 19, [])
79 |
80 | def test_parse_response_corrupted_data(self, pb):
81 | data = b'\xd1\x91\xd0\xb6'
82 | msg_buffer = 100
83 | with pytest.raises(Exception) as exc:
84 | pb.parse_response(data, msg_buffer)
85 | assert 'Message parse error:' in str(exc.value)
86 |
87 | def test_parse_response_wrong_msg_type(self, pb):
88 | data = b'\x86\x00\x04\x00\x13test\x001234\x00745\x00abcde'
89 | msg_buffer = 100
90 | with pytest.raises(BlynkError) as b_err:
91 | pb.parse_response(data, msg_buffer)
92 | assert "Unknown message type: '134'" in str(b_err.value)
93 |
94 | def test_parse_response_msg_hw_unicode(self, pb):
95 | data = b'\x14\x00\x02\x00\x04\xd1\x91\xd0\xb6'
96 | msg_buffer = 1024
97 | result = pb.parse_response(data, msg_buffer)
98 | assert result == (20, 2, 4, [u'ёж'])
99 |
100 | def test_heartbeat_msg(self, pb):
101 | result = pb.heartbeat_msg(20, 2048)
102 | assert result == b'\x11\x00\x01\x00+ver\x000.2.6\x00buff-in\x002048\x00h-beat\x0020\x00dev\x00python'
103 |
104 | def test_login_msg(self, pb):
105 | result = pb.login_msg('1234')
106 | assert result == b'\x02\x00\x01\x00\x041234'
107 |
108 | def test_ping_msg(self, pb):
109 | result = pb.ping_msg()
110 | assert result == b'\x06\x00\x01\x00\x00'
111 |
112 | def test_response_msg(self, pb):
113 | result = pb.response_msg(202)
114 | assert result == b'\x00\x00\x01\x00\x03202'
115 |
116 | def test_virtual_write_msg(self, pb):
117 | result = pb.virtual_write_msg(127, 'abc', 123)
118 | assert result == b'\x14\x00\x01\x00\x0evw\x00127\x00abc\x00123'
119 |
120 | def test_virtual_sync_msg(self, pb):
121 | result = pb.virtual_sync_msg(1, 24)
122 | assert result == b'\x10\x00\x01\x00\x07vr\x001\x0024'
123 |
124 | def test_email_msg(self, pb):
125 | result = pb.email_msg('a@b.com', 'Test', 'MSG')
126 | assert result == b'\r\x00\x01\x00\x10a@b.com\x00Test\x00MSG'
127 |
128 | def test_tweet_msg(self, pb):
129 | result = pb.tweet_msg('tweet_msg_test')
130 | assert result == b'\x0c\x00\x01\x00\x0etweet_msg_test'
131 |
132 | def test_notify_msg(self, pb):
133 | result = pb.notify_msg('app_msg_test')
134 | assert result == b'\x0e\x00\x01\x00\x0capp_msg_test'
135 |
136 | def test_set_property_msg(self, pb):
137 | result = pb.set_property_msg(10, 'color', '#FF00EE')
138 | assert result == b'\x13\x00\x01\x00\x1010\x00color\x00#FF00EE'
139 |
140 | def test_internal_msg(self, pb):
141 | result = pb.internal_msg('rtc', 'sync')
142 | assert result == b'\x11\x00\x01\x00\x08rtc\x00sync'
143 |
--------------------------------------------------------------------------------