Coder Social home page Coder Social logo

lib-python's Introduction

SWUbanner

Blynk Python Library

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.

GitHub version GitHub download GitHub stars GitHub issues Build Status License

If you like Blynk - give it a star, or fork it and contribute! GitHub stars GitHub forks

Blynk Banner

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.

  • 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. Full list of supported hardware can be found here.

  • 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.

  • 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.

Installation of Blynk Python Library

Installation via python pip

  • Check python availability in your system.

    python --version
    

    To exclude compatibility issue preferable versions are Python 2.7.9 (or greater) or Python 3.4 (or greater) If python not present you can download and install it from here.

    NOTE: To run python in "sandbox" you can try virtualenv module. Check this document how to do it.

  • If you’re using preferable versions of python mentioned above, then pip comes installed with Python by default. Check pip availability:

    pip --version
    
  • Install blynk library

    sudo pip install blynklib
    

Manual installation

Library can be installed locally from git sources:

git clone https://github.com/blynkkk/lib-python.git
cd lib-python
pip install --user -e .

# sudo pip install -e .  # if installation needed not for current but for all users

Testing

You can run unit tests for cPython version of library (blynklib.py) using the command:

python setup.py test

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

NOTE: Unit tests for Micropython ENV are not available yet.

Micropython installation

Some hardware platforms can use Micropython package. This is helpful for preliminary testing and debugging of your code outside of real hardware. Supported platforms and related installation docs can be found here.

Features

This library supports Python2, Python3 (blynklib.py) , and Micropython (blynklib_mp.py).

  • Communication with public or local Blynk Server.
  • Exchange any data between your hardware and app
  • Tested to work with: Raspberry Pi (any), ESP32, ESP8266
List of available operations:
  • Subscribe to connect/disconnect events (ssl connection supported only by cPython lib)
  • Subscribe to read/write events of virtual pins
  • Virtual Pin write
  • Virtual Pin sync
  • Send mobile app push notifications
  • Send email notifications
  • Send twitter notifications
  • Change widget GUI parameters in Blynk app based on hardware input

Quickstart

  1. Install Blynk python library as described above
  2. Install Blynk App: Google Play | App Store
  • Create new account in Blynk app using your email address
  • Create a new Project in Blynk app
  • You will get Auth Token delivered to your email account.
  • Put this Auth Token within your python script to authenticate your device on public or local
BLYNK_AUTH = '<YourAuthToken>' #insert your Auth Token here

Usage example

import blynklib
# import blynklib_mp as blynklib # micropython import

BLYNK_AUTH = '<YourAuthToken>' #insert your Auth Token here
# base lib init
blynk = blynklib.Blynk(BLYNK_AUTH)
 
# advanced options of lib init
# from __future__ import print_function
# blynk = blynklib.Blynk(BLYNK_AUTH, server='blynk-cloud.com', port=80, ssl_cert=None,
#                        heartbeat=10, rcv_buffer=1024, log=print)

# Lib init with SSL socket connection
# blynk = blynklib.Blynk(BLYNK_AUTH, port=443, ssl_cert='<path to local blynk server certificate>')
# current blynk-cloud.com certificate stored in project as 
# https://github.com/blynkkk/lib-python/blob/master/certificate/blynk-cloud.com.crt
# Note! ssl feature supported only by cPython

# register handler for Virtual Pin V22 reading by Blynk App.
# when a widget in Blynk App asks Virtual Pin data from server within given configurable interval (1,2,5,10 sec etc) 
# server automatically sends notification about read virtual pin event to hardware
# this notification captured by current handler 
@blynk.handle_event('read V22')
def read_virtual_pin_handler(pin):
    
    # your code goes here
    # ...
    # Example: get sensor value, perform calculations, etc
    sensor_data = '<YourSensorData>'
    critilcal_data_value = '<YourThresholdSensorValue>'
        
    # send value to Virtual Pin and store it in Blynk Cloud 
    blynk.virtual_write(pin, sensor_data)
    
    # you can define if needed any other pin
    # example: blynk.virtual_write(24, sensor_data)
        
    # you can perform actions if value reaches a threshold (e.g. some critical value)
    if sensor_data >= critilcal_data_value
        
        blynk.set_property(pin, 'color', '#FF0000') # set red color for the widget UI element 
        blynk.notify('Warning critical value') # send push notification to Blynk App 
        blynk.email(<youremail@email.com>, 'Email Subject', 'Email Body') # send email to specified address
        
# main loop that starts program and handles registered events
while True:
    blynk.run()

Other Examples

Examples can be found here Check them all to get familiar with main Blynk API features.

Core operations:
Raspberry Pi (any):

Read Raspberry Pi guide first.

ESP32

Read ESP32 guide first.

ESP8266

Read ESP8266 guide first.

Memory size limitations

For hardware with limited memory size (ex. ESP8266) you can use frozen modules or frozen bytecode approaches to load blynklib or any other library to hardware.

Read this document to get more information.

Documentation and other helpful links

Full Blynk Documentation - a complete guide on Blynk features

Community (Forum) - join a 1'000'000 Blynk community to ask questions and share ideas

Official Website

Social Media:

Facebook Twitter Youtube

Instagram LinkedIn

Blynk libraries for other platforms

Contributing

You are very welcome to contribute: stability bugfixes, new hardware support, or any other improvements. Please.

License

This project is released under The MIT License (MIT)

lib-python's People

Contributors

antohaua avatar blynkkk avatar bradenm avatar delilovic avatar egueli avatar fgervais avatar icetomcat avatar smankusors avatar vitormhenrique avatar vshymanskyy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lib-python's Issues

RTC widget supported?

I see some hooks for the internal_ message types and pins (which is where the RTC ends up), but it's no not clear how to wire this up to retrieve the current date/time in the app-specified timezone from the server..

An example of using the RTC widget, even if to just push the resulting date/time into a display, would be quite useful.

Some socket reads use SOCK_MAX_TIMEOUT and other uses SOCK_TIMEOUT

I was trying to figure out why it seemed like packets were being queued in the esp8266 wifi layer, and found that in the various RX paths there are different timeouts passed. By default, SOCK_MAX_TIMEOUT is const(5), while SOCK_TIMEOUT is 0.05. Consequently, some but not all reads are affected by a 50ms timeout rather than a 5 second one.

The right fix seems to be to remove one of them and use one value, unless there's a good reason to sometimes only wait 50ms for a response from the server?

Virtual pin read event handler not working

# register handler for virtual pin V11 reading
@blynk.handle_event('read V11')
def read_virtual_pin_handler(pin):
    print(READ_PRINT_MSG.format(pin))
    blynk.virtual_write(pin, random.randint(0, 255))

Code directly from the example, however read trigger is not occurring.
Device - Raspberry Pi 3B+ with Python 3.5.3

Joystick don't send 2nd value from blynk app

Hello, developers!
This is an awesome module for Python and I want to explore it more. But I face an issue while working with it.
Have some kinda vehicle that doesn't receive the 2nd parameter (I spin the joystick in different positions, below is an example of output) and I don't get why I can't read it from value[1] - is always a zero...

Code:

    @blynk.handle_event('write V2')
    def write_virtual_pin_handler(pin, value):
        Controller(pin="V2", x_coord=value[0], y_coord=value[1])
        print("Write: ", WRITE_EVENT_PRINT_MSG.format(pin, value))

Output:

     Write:  [WRITE_VIRTUAL_PIN_EVENT] Pin: V2 Value: '['52', '0']'

2021-03-14 03 15 20

Sensor disconnected Using two BLYNK_AUTH on Raspberry Pi2

I try to get help from Blynk community without getting an answer right now.
I wrote two different python script on Raspberry Pi.
The two script are very different, first one control some RF outlets using an RF transmitter, second one read temp and humidity from a DHT22 sensor.
Each scripts will connect to internal Blynk server using different tokens. In this way is possible to identify the Raspberry PI as two different sensors on the Blynk server. The DHT script will also write temperature and humidity on Influx DB (but this not concerning this problem).

Randomly the DHT script will get disconnected from Blynk server, strangely no "onDisconnect" handler is called (so none can inform the script that disconnection happened); even more strange is the fact that the Blynk server is still updated with the temperature and humidity sent by readEventHandler timely called by BlynkTimer.
I'm suspecting the problem is in the library: the script use the same Blynk init routine:

 def initBlynk(self):

    # blynk main object
    blynk = Blynk(
        token=self.cfg.get("blynk", "token"),
        server=self.cfg.get("blynk", "server"),
        port=self.cfg.get("blynk", "port"))

    # Blynk timer
    timer = BlynkTimer()

    """
    Assign switch write and read events:
    - write events triggered  to set value
    - read event sent sensor value
    """

    def readEventHandler(pin):
        self.log.debug("READ EVENT FOR VPIN {}".format(pin))
        self.sendSensorValue(pin)

    def writeEventHandler(pin, value):
        # we does not set anythings
        self.log.debug("WRITE EVENT VPIN {} VALUE {}".format(pin, value))
        self.sendSensorValue(pin)

    # decorating
    for vpin in self.cfg["sensor"]["vpins"].split(','):
        self.log.debug("BLYNK Decorating READ/WRITE FOR VPIN {}".format(vpin))
        # Read Event
        Blynk.handle_event(blynk, "read v{}".format(vpin))(readEventHandler)
        # Write Event
        Blynk.handle_event(blynk, "write v{}".format(vpin))(writeEventHandler)
        # Timer Event
        BlynkTimer.register(
            timer, pin=vpin, interval=BLYNK_UPDATE_INTERVAL, run_once=False)(
                readEventHandler)

    #On connect Event
    Blynk.handle_event(blynk, "connect")(self.onConnectHandler)
    #On Disconnect Event
    Blynk.handle_event(blynk, "disconnect")(self.onDisconnectHandler)


    # Globally saving the handlers
    self._handlers.append(writeEventHandler)
    self._handlers.append(readEventHandler)

    # Saving blynk and timer object
    self._blynk = blynk
    self._timer = timer

    return self.isConneted()

How long a simple blynk.run() from examples complete?

Hi all there in this uPy community. I was debugging tons of code ending to test a simple example like terminal at ESP32, https://github.com/blynkkk/lib-python/blob/master/examples/esp32/02_terminal_cli.py.

I just uploaded that script only editing to have an idea of how long run() takes to other things in main loop. Im running at ESP32 standard 2020 FW version.

while True:
LoopStarts = time.time()
blynk.run()
LoopEnds = time.time()
delta = LoopEnds - LoopStarts
print('---->> Delta RunLoop :', delta)

here my results, with fast (0) / slow (~60+ secs) cicles.

All registered pins like this example v2 works in real time, but Im wondering what I m not doing well as we need more than run() timeslots !

Hints ?

  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ for Python v0.2.6

                 Blynk updated

---------->> Delta RunLoop : 0
---------->> Delta RunLoop : 14
---------->> Delta RunLoop : 64
---------->> Delta RunLoop : 0
---------->> Delta RunLoop : 65
---------->> Delta RunLoop : 0
---------->> Delta RunLoop : 63
---------->> Delta RunLoop : 0
---------->> Delta RunLoop : 65
---------->> Delta RunLoop : 0
---------->> Delta RunLoop : 63
---------->> Delta RunLoop : 0
---------->> Delta RunLoop : 65

Not working 👎🏻

using the example with the BLYNK_AUTH_TOKEN.

root@ServidorPrincipalCasa:/home# python3 -V
Python 3.7.3
root@ServidorPrincipalCasa:/home# chmod -Rf 777 blynk3.py && python3 blynk3.py

    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ for Python v0.2.0 (Linux)

Invalid auth token
^CTraceback (most recent call last):
  File "blynk3.py", line 17, in <module>
    blynk.run()
  File "/usr/local/lib/python3.7/dist-packages/BlynkLib.py", line 246, in run
    data = self.conn.recv(self.buffin)
KeyboardInterrupt
root@ServidorPrincipalCasa:/home# chmod -Rf 777 blynk3.py && python blynk3.py
Traceback (most recent call last):
  File "blynk3.py", line 1, in <module>
    import BlynkLib
ImportError: No module named BlynkLib
root@ServidorPrincipalCasa:/home# pip install blynklib
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Requirement already satisfied: blynklib in /usr/local/lib/python2.7/dist-packages (0.2.6)
root@ServidorPrincipalCasa:/home#

Invalid auth token for Blynk console 2.0

Is blynk going to update this library with support for console 2.0?

https://github.com/blynkkk/blynk-library
https://github.com/vshymanskyy/blynk-library-python

I used the token from:
https://blynk.cloud/dashboard/...

import time
import logging
import BlynkLib

BLYNK_AUTH = 'auth code' #insert your Auth Token here

# initialize Blynk
blynk = BlynkLib.Blynk(BLYNK_AUTH)

# @blynk.on("connected")
# def connect_handler(ping):
#     print('Blynk connected')

# @blynk.on("disconnected")
# def disconnect_handler():
#     print('Blynk disconnected')

print('starting device...')

# main loop that starts program and handles registered events
try:
    while True:
        blynk.run()
except KeyboardInterrupt:
    blynk.disconnect()
    print("Blynk disconnected!")

Error message

    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ for Python v0.2.0 (Darwin)

starting device...
Invalid auth token

"AttributeError: type object 'Blynk' has no attribute 'handle_event'"

Hello i was having problems on a raspberry pi with reading and writing to virtual pins .
I was getting errors "AttributeError: type object 'Blynk' has no attribute 'handle_event'"
When i was running the python script i was getting this:
___ __ __
/ _ )/ /_ _____ / /__
/ _ / / // / _ / '/
/
//_, /////_
/
__/ for Python v0.2.0 (Linux)
Even after i updated from pip where it says its v0.2.6
so i dug deeper and show that there was two files for blynklib.py and BlynkLib.py of witch 1 was v0.2.0 and the other v0.2.6 , i replaced the BlynkLib.py with the blynklib.py and the problem was fixed

runonce= True example.

I was trying the examples here using for instance
https://github.com/blynkkk/lib-python/blob/master/TIMERS.md

so that is ok including one time timer, but that is just issued at the start of the python script. I m looking for an example where I set if some condition got true then i need to set a timer after that moment.

I m familiar with normal C blynktimer code and setup & behavior, but still don't understand this python library.

any hint?
thanks!

Memory errors

MicroPython v1.9.4-927-g7565eb7 on 2018-11-08; XBC LTE Cat 1 Verizon with EFM32G
Type "help()" for more information.

Loading /flash/main.mpy...
Running bytecode...
Traceback (most recent call last):
File "", line 1, in
MemoryError: memory allocation failed, allocating 272 bytes

SSL Support and msg id issue

So there's issue when I want to implement the SSL support. The id for message that sent to the server starts with 2, not 1. The blynk-server expects hardware sent with id starting from 1, but the library starts from 2 instead. (Code : blynklib.py#L70-L79)

First, server checks that if it's HTTP protocol, then checks if it's from hardware, and then fallback to app pipeline. This works with HTTP (port 80 and 8080) because even it's fallback to the app pipeline, the server never expects it, so it get redirected to hardware pipeline. On the HTTPS (port 443 and 9443), the server expects this is app, but the library sent the hardware messages, and the server not really understand and completely ignore it. Resulting "Auth stage timeout" in the python library.

So actually I already implemented ssl wrapper on the code, but not actually verified the server certificate. I set _msg_id = 0 and it's fully worked. But then I'm confused... is this really intended that... if _msg_id over 65535, then we will use 1 forever?

Thanks,

Blynk 2.0 auth not working

The example not working. I can't connect my device with this blynkkk/lib-python library, it print blynklib.BlynkError: Auth stage failed. Status=4.

It work well with vshymanskyy/blynk-library-python.

I'm so confuse which library should i use, on vshymanskyy/blynk-library-python documentation didn't sync with new blynk docs (lack of documentation). By use official library blynkkk/lib-python, it can't run even the example.

Device info: Raspberry Pi
Library version: blynkkk/lib-python 0.2.6
Mobile App: Blynk IoT 1.5.6 not the legacy one
Device and Token was generated on Web blynk.cloud.

Broken connection to cloud server is not detected with Ping and never restored

There is an issue with the connection monitoring with the Ping mechanism.

This can be reproduced with this simple example program:

import blynklib
import time


BLYNK_AUTH =  # insert your Auth Token here

CONNECT_PRINT_MSG = '[CONNECT_EVENT]'
DISCONNECT_PRINT_MSG = '[DISCONNECT_EVENT]'

@blynk.handle_event("connect")
def connect_handler():
    print(CONNECT_PRINT_MSG)

@blynk.handle_event("disconnect")
def connect_handler():
    print(DISCONNECT_PRINT_MSG)

###########################################################
# infinite loop that waits for event
###########################################################
while True:
    blynk.run()

When running this program with a working network connection it prints the [CONNECT_EVENT] message but when unplugging the network cable the disconnect event is never printed. When plugging the cable back in the connection is not restored.

This seem to be due to the is_server_alive() check in the blynk lib. The following statement never returns False:

        if rcv_delta > h_beat_ms + (h_beat_ms // 2):
            return False

because rcv_delta is always 0 as _last_rcv_time is updated after each receive(), even if this fails.
Can someone of the developers here please have a look at this? Thanks.

Unable to import blynklib while using esp8266

I am trying to experiment with blynk using an esp8266 and programming on thonny. I have the correct library installed, however, the ampy migration of files from the library to the board does not seem to work. It always says the esp8266 tutorial wants me to move is not found.

virtual_write for map widget point updates

hi all. I'm struggling with this python lib trying to update points in a blynk app map/

I was reading https://community.blynk.cc/t/solved-maps-with-http-rest-api/15826/54 where a possible solution is to use that REST API to update.
Also https://community.blynk.cc/t/blynk-map-interface-update-from-blynk-library-python/27289 without a solution.

how I can update a map widget here with python lib, I fact I'm using an ESP32 running last official Micropython 1.15.
any hint?
thanks in advance.

M

unicode if else on blynk switch

hi there ...

I am not quite sure if it is an issue.

I use the following snippet from the examples extended by an if else

# register handler for virtual pin V0 write event
@blynk.handle_event('write V0')
def write_virtual_pin_handler(pin, value):
  print(value)
  if value == 1:
    execOS("/sbin/relays.sh set DOUT")
    print("Solenoid on")
  else:
    execOS("/sbin/rekays.sh clear DOUT")
    print("Solenoid off"``

this gives me the following output when pushing a switch in the blynk app on V0

image

why is value in unicode, why are there squared brackets, where do they come from and how can i get rid of them? Adding an int(value) into the print statement gives me no output at all. Not even the if else is executed anymore.

i am programming for over thirty years now, but i am new to python. sadly not too impressed up to now how poorly python tells me what could be wrong.

thanks for reading guys.
heiterkiter

Blynk 2.0 auth not working #2

Same issue here,
The example not working. I can't connect my device with this blynkkk/lib-python library, it print blynklib.BlynkError: Auth stage failed. Status=4.

Is this library dead since Blynk 2.0 ?

Client doesn't reconnect after lost connection is restored

I'm using private blynk server and python libs on Raspberry Pi.
Problem is that once network connection to the server is interrupted, so that heartbeat is missed, even after network connectivity is restored client doesn't return online and only way to restore it is to restart python script.
Steps to reproduce:
Setup private blynk server (same thing happens on Blynk Cloud server).
Use example script with logging.
After connection to server is established, interrupt somehow connectivity to the server (with firewall rule or by turning off router for 10 seconds).
Result is following:

Dec 25 13:03:46 raspberrypi python[21730]: 2019-12-25 13:03:46,397 [INFO]  Connected to blynk server
Dec 25 13:03:46 raspberrypi python[21730]: 2019-12-25 13:03:46,398 [INFO]  Authenticating device...
Dec 25 13:03:46 raspberrypi python[21730]: 2019-12-25 13:03:46,403 [INFO]  Access granted
Dec 25 13:03:46 raspberrypi python[21730]: 2019-12-25 13:03:46,406 [INFO]  Heartbeat = 10 sec. MaxCmdBuffer = 1024 bytes
Dec 25 13:03:46 raspberrypi python[21730]: 2019-12-25 13:03:46,407 [INFO]  Registered events: ['write v19', 'write v18', 'write v11', 'write v10', 'write v13', 'write v12', 'writ
Dec 25 13:03:56 raspberrypi python[21730]: 2019-12-25 13:03:56,442 [INFO]  Heartbeat time: 1577275436441
Dec 25 13:03:56 raspberrypi python[21730]: 2019-12-25 13:03:56,447 [INFO]  Response status: 200
Dec 25 13:04:06 raspberrypi python[21730]: 2019-12-25 13:04:06,488 [INFO]  Heartbeat time: 1577275446488
Dec 25 13:04:06 raspberrypi python[21730]: 2019-12-25 13:04:06,492 [INFO]  Response status: 200
Dec 25 13:04:16 raspberrypi python[21730]: 2019-12-25 13:04:16,529 [INFO]  Heartbeat time: 1577275456528
Dec 25 13:04:26 raspberrypi python[21730]: 2019-12-25 13:04:26,566 [INFO]  Heartbeat time: 1577275466566
Dec 25 13:04:36 raspberrypi python[21730]: 2019-12-25 13:04:36,582 [INFO]  Heartbeat time: 1577275476582
Dec 25 13:04:46 raspberrypi python[21730]: 2019-12-25 13:04:46,587 [INFO]  Heartbeat time: 1577275486587
Dec 25 13:04:56 raspberrypi python[21730]: 2019-12-25 13:04:56,591 [INFO]  Heartbeat time: 1577275496591
Dec 25 13:05:06 raspberrypi python[21730]: 2019-12-25 13:05:06,595 [INFO]  Heartbeat time: 1577275506595
Dec 25 13:05:16 raspberrypi python[21730]: 2019-12-25 13:05:16,599 [INFO]  Heartbeat time: 1577275516599
Dec 25 13:05:26 raspberrypi python[21730]: 2019-12-25 13:05:26,603 [INFO]  Heartbeat time: 1577275526603
Dec 25 13:05:36 raspberrypi python[21730]: 2019-12-25 13:05:36,607 [INFO]  Heartbeat time: 1577275536607
Dec 25 13:05:46 raspberrypi python[21730]: 2019-12-25 13:05:46,611 [INFO]  Heartbeat time: 1577275546611
Dec 25 13:05:56 raspberrypi python[21730]: 2019-12-25 13:05:56,615 [INFO]  Heartbeat time: 1577275556615
Dec 25 13:06:06 raspberrypi python[21730]: 2019-12-25 13:06:06,619 [INFO]  Heartbeat time: 1577275566619
Dec 25 13:06:16 raspberrypi python[21730]: 2019-12-25 13:06:16,623 [INFO]  Heartbeat time: 1577275576623
Dec 25 13:06:26 raspberrypi python[21730]: 2019-12-25 13:06:26,627 [INFO]  Heartbeat time: 1577275586627

As you can see, there is no any response from server (even though connection was interrupted only for short while).

In my opinion it should be detected that there is no response and reconnecting attempt should be made.

Anyway, if there is no way to fix this in library, is there a way to fix it in my python script?

Displaying OpenWeather Data on Blynk Gauge

I am not using any weather sensors as I want to display the data that is coming from the web on my Blynk gauge. I am currently using OpenWeather API, and Blynk 2.0. May I please know if there is a way around of doing this.

virtual_sync function doesn't fire with all pins passed as arguments

I designed an app with 4 "push" button (virtual pin assigned starting from V0 to V3) and 4 value display (V10 ... V13). I use virtual pins V10 ... V13 for storing "status" (color) of each button (V10 for button V0, V11 for button V1, ...) and I used value display just for debug.
When I press a button (release event are ignored), the script changes the color of button I pressed and stores a value (depending on color) on the corresponding pin used for "status".
I'd like to use virtual_sync with pins V10...V13 to restore "status" of buttons when starting the app (during connection event). I tried the script attached below, but virtual_sync fires only the first two times.

This is the version of software and hardware I used, I don't know if the strange behavior depends on it:
Blynk App version: 2.27.5
Blynk server: Blynk Cloud
Hardware: Raspberry Pi B rev2
S.O.: Linux raspberrypi 4.9.35
Python: ver. 2.7.9 and 3.4.2

Some logs:

2019-06-21 10:46:42,695 [INFO]  Connected to blynk server
2019-06-21 10:46:42,698 [INFO]  Authenticating device...
2019-06-21 10:46:42,731 [INFO]  Access granted
2019-06-21 10:46:42,764 [INFO]  Heartbeat = 10 sec. MaxCmdBuffer = 1024 bytes
2019-06-21 10:46:42,768 [INFO]  Registered events: ['write v19', 'write v18', 'write v11', 'write v10', 'write v13', 'write v12', 'write v15', 'write v14', 'write v17', 'write v16', 'write v9', 'write v8', 'connect', 'write v1', 'write v0', 'write v3', 'write v2', 'write v5', 'write v4', 'write v7', 'write v6', 'disconnect', 'write v20', 'write v21', 'write v22', 'write v23', 'write v24', 'write v25', 'write v26', 'write v27', 'write v28', 'write v29', 'write v32', 'write v31', 'write v30']

2019-06-21 10:46:42,773 [INFO]  Event: ['connect'] -> ()
2019-06-21 10:46:42,776 [INFO]  [CONNECT_EVENT]
2019-06-21 10:46:42,782 [INFO]  RUN ...
2019-06-21 10:46:42,810 [INFO]  Event: ['write v10'] -> (10, [u'10'])
2019-06-21 10:46:42,814 [INFO]  [SYNC_FROM_STORAGE] S(10,[u'10']) -> Pin: V0
2019-06-21 10:46:42,818 [INFO]  [WRITE_VIRTUAL_PIN_EVENT] Pin: V0 Value: 1 Storage: V10
2019-06-21 10:46:42,838 [INFO]  Event: ['write v11'] -> (11, [u'20'])
2019-06-21 10:46:42,842 [INFO]  [SYNC_FROM_STORAGE] S(11,[u'20']) -> Pin: V1
2019-06-21 10:46:42,846 [INFO]  [WRITE_VIRTUAL_PIN_EVENT] Pin: V1 Value: 0 Storage: V11
2019-06-21 10:46:42,865 [INFO]  Response status: 200
2019-06-21 10:46:42,893 [INFO]  Response status: 200
2019-06-21 10:46:52,874 [INFO]  Heartbeat time: 1561106812873

script.py

import os
import logging
import blynklib

BLYNK_AUTH = 'something'

# virtual pins
STANDARD_VPIN = [0,1,2,3] # virtual pins assigned to push buttons
STORAGE_VPIN = [10,11,12,13] # virtual pins assigned to value displays
# blynk color
ON_COLOR = '#FFE60C' # yellow
OFF_COLOR = '#FFFFFF' # withe

syncing = 0

# logging variables
LOG_FORMAT = "%(asctime)s: %(message)s"
DATE_FORMAT = "%D:%H:%M:%S"
WRITE_EVENT_PRINT_MSG = "[WRITE_VIRTUAL_PIN_EVENT] Pin: V{} Value: {} Storage: V{}"
SYNC_EVENT_PRINT_MSG = "[SYNC_FROM_STORAGE] S({},{}) -> Pin: V{}"
CONNECT_PRINT_MSG = '[CONNECT_EVENT]'
DISCONNECT_PRINT_MSG = '[DISCONNECT_EVENT]'

_log = logging.getLogger('BlynkLog')
logFormatter = logging.Formatter("%(asctime)s [%(levelname)s]  %(message)s")
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
_log.addHandler(consoleHandler)
_log.setLevel(logging.DEBUG)

# initialize Blynk 
blynk = blynklib.Blynk(BLYNK_AUTH,log=_log.info)

@blynk.handle_event("connect")
def connect_handler():
    global syncing
    _log.info(CONNECT_PRINT_MSG)
    syncing = 1
    for pin in STORAGE_VPIN:
        blynk.virtual_sync(pin)
#    blynk.virtual_sync(*STORAGE_VPIN)
    syncing = 0

@blynk.handle_event("disconnect")
def disconnect_handler():
    _log.info(DISCONNECT_PRINT_MSG)

@blynk.handle_event('write V*')
def write_virtual_pin_handler(v_pin, value):
    if v_pin in STANDARD_VPIN:
        standard_action(v_pin, value)
    elif v_pin in STORAGE_VPIN:
        storage_action(v_pin, value)

def standard_action(v_pin, value):
    _log.info("STANDARD action")
    if int(value[0]) == 1:
        toggle_switch(v_pin)

def storage_action(s_pin, value):
    v_pin = s_pin - 10
    _log.info(SYNC_EVENT_PRINT_MSG.format(s_pin,value,v_pin))
    if int(value[0]) == 10:
        turn_on(v_pin)
    elif int(value[0]) == 20:
        turn_off(v_pin)

def turn_on(v_pin):
    blynk.set_property(v_pin, 'color', ON_COLOR)
    # write on storage pin
    if not syncing:
        blynk.virtual_write(v_pin+10, 10)
    _log.info(WRITE_EVENT_PRINT_MSG.format(v_pin, 1, v_pin+10 ))

def turn_off(v_pin):
    blynk.set_property(v_pin, 'color', OFF_COLOR)
    # write on storage pin
    if not syncing:
        blynk.virtual_write(v_pin+10, 20)
    _log.info(WRITE_EVENT_PRINT_MSG.format(v_pin, 0, v_pin+10))

num = 0
def toggle_switch(v_pin):
    global num
    mod = num % 2
    if mod > 0:
        turn_off(v_pin)
    else:
        turn_on(v_pin)
    num +=1

def main():
    _log.info('STARTING PID: {}'.format(os.getpid()))
    try:
        while True:
            blynk.run()
    except KeyboardInterrupt:
        for pin in STANDARD_VPIN:
            blynk.set_property(pin, 'color', '#FF0000')
        blynk.disconnect()
    _log.info('STOP')
        
if __name__ == "__main__":
    main()

Update Time Input Widget

Hello

Any idea how to update a Time Input Widget with start/stop input?

This is the format which I receive from the widget: [u'', u'', u'Europe/Vienna', u'', u'3600']

[0] time in seconds from
[1] time in seconds to
[2] time zone
[3] no idea
[4] maybe PM or AM

I tried to send the same array back but it didn't work, hmmm.

Best Regards

@antohaUa maybe?

BlynkTimer Broken on Low Memory Ports

Expected Behavior

Registering a Timer via register decorator should work on devices with low memory.

Actual Behavior

An AttributeError is raised, complaining that a function object has no attribute 'func', as this seems to be the current fallback if a __name__ attribute cannot be found. This completely breaks BlynkTimer on low memory ports.

Steps to Reproduce the Problem

from blynktimer import Timer

timer = Timer()

@timer.register(interval=1)
def test():
   print('Hello!')

while 1:
   timer.run()

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "main.py", line 8, in start
 File "/lib/blynktimer.py", line 58, in __init__
 File "/lib/blynktimer.py", line 48, in _get_func_name
AttributeError: 'function' object has no attribute 'func'

Specifications

  • Version: MicroPython Official v1.11.0
  • Platform: ESP8266

How to use LCD with python library?

An example appears in the app while creating LCD:

lcd.print(0,0,"Hello")

Is this the correct way to use the lcd from python? How to declare the LCD object?

updating a global variable inside a weather like script

Hi there im trying to update a global variable (T_MIN4CF) via a slider widget.
all the rest works ok but as soon I move the slider related to T_MIN4CF variable the program brakes.
here the error and below the simple original code.

Any idea?

pi@raspizero:~/python/lib-python $ python3 multiTermy.py

    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ for Python v0.2.4

Traceback (most recent call last):
File "multiTermy.py", line 148, in
File "/home/pi/python/lib-python/blynktimer.py", line 88, in run
timers_intervals = [curr_timer.run() for curr_timer in Timer.timers.values() if not curr_timer.stopped]
File "/home/pi/python/lib-python/blynktimer.py", line 88, in
timers_intervals = [curr_timer.run() for curr_timer in Timer.timers.values() if not curr_timer.stopped]
File "/home/pi/python/lib-python/blynktimer.py", line 113, in run
self.deco(*self.args, **self.kwargs)
File "multiTermy.py", line 103, in updateBlynkServer
TypeError: unorderable types: float() <= list()

code;:

termy3 - Copy.txt

Cannot authenticate to server and test fail

Hi,
Im trying to setup blynk and start using the platform.
Unfortunately I have faced a number of issues.

I started by installing the library and running it on my PC (not embedded device)
Running python setup.py test fails on a test:

E       assert 1 == 0
E         +1
E         -0

test\test_blynk_protocol.py:26: AssertionError

And when I run the library with the following code:

import blynklib
BLYNK_AUTH = 'vXFXq8rp0y10GtYUl9bL2J_c81AFTVyz'
print("Connecting to Blynk server...")
blynk = blynklib.Blynk(BLYNK_AUTH)
print("connecting to server...")
blynk.connect()
print("ststus: {}".format(str(blynk.connected())))
print("starting up server")
while True:
    blynk.run()

It returns:
[ERROR]: Invalid Auth Token
I have manually modified the server from blynk-cloud.com to blynk.cloud and then it returns:
Authenticating device...
[ERROR]: Auth stage failed. Status=4

Would appreciate your help :)

Update blynk timer interval

Hello,

I can not figure out how to update the interval of an already created timer. Or if this is not possible, how can you recycle a created timer, the stop function does not delete the timer.

Thanks

@antohaUa maybe?

How can I read multiple sensor data with blynk app and python?

Hello,

I am trying to connect a bunch of sensors to my ESP32. I want to connect it to the Blynk app in order to get some data on my phone.

I am currently coding on python, however, I have an issue.

The code seems to always stop after it reads the light sensor. Basically, I only get the data from the light sensor and it loops from there.

Any clue what is wrong with the code?

import network
from time import sleep
import machine
import onewire, ds18x20
import dht
from machine import Pin
import blynklib_mp as blynklib

"""--- Connect to WiFi ---"""
WIFI_SSID = '******'
WIFI_PASS = '******'
BLYNK_AUTH = '*********'

print("Connecting to WiFi network '{}'".format(WIFI_SSID))
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
wifi.connect(WIFI_SSID, WIFI_PASS)
while not wifi.isconnected():
    sleep(0.1)
    print('.', end="")

print('\nWiFi IP:', wifi.ifconfig()[0])

"""--- Connect to Blynk Server ---"""
print("Connecting to Blynk server...")
blynk = blynklib.Blynk(BLYNK_AUTH)


"""--- Settings ---""" 

#LIGHT
light_PIN = 35
blynk_VPIN_Light = 0
light_RAW = machine.ADC(machine.Pin(light_PIN))
light_RAW.atten(machine.ADC.ATTN_11DB)

#MOISTURE
moisture_PIN = 34
blynk_VPIN_Moisture = 1
moisture_RAW = machine.ADC(machine.Pin(moisture_PIN))               
moisture_RAW.atten(machine.ADC.ATTN_11DB)
moisture_PWM_PIN = 25
moisture_RAW_MIN = 20
moisture_RAW_MAX = 3600

#SOIL TEMPERATURE
soil_temperature_PIN = 4
blynk_VPIN_Soil_Temp = 2
ds_pin = machine.Pin(soil_temperature_PIN)
soil_temperature_RAW = ds18x20.DS18X20(onewire.OneWire(ds_pin))
roms = soil_temperature_RAW.scan()

#AIR TEMPERATURE HUMIDITY
blynk_VPIN_Air_Temp = 3
blynk_VPIN_Air_Hum = 4
sensor = dht.DHT22(Pin(33))



@blynk.handle_event('read V{}'.format(blynk_VPIN_Light))
def read_handler(vpin):

    """--- Light Sensor ---""" 
    #WHILE LOOP
    print('Light RAW: ',light_RAW.read())
    sleep(1)
    blynk.virtual_write(blynk_VPIN_Light, light_RAW.read())

    """--- Moisture Sensor ---""" 
    #WHILE LOOP
    moisture_PWM = machine.PWM(machine.Pin(moisture_PWM_PIN), freq=600, duty=512)       #Send a PWM signal of 600 kHz to pin 25 with a dutycycle of 50%
    sleep(0.2)                                                                          #Allow the circuit to stabilize 
    moisture_Cumulative_RAW = 0
    for _ in range(20):
        moisture_Cumulative_RAW = moisture_Cumulative_RAW + moisture_RAW.read()         #Read data from analog pin 34 and add it to MoistLevel variable
        sleep(0.05)
        if moisture_RAW.read() < moisture_RAW_MIN:
            moisture_RAW_MIN = moisture_RAW.read()
        if moisture_RAW.read() > moisture_RAW_MAX:
            moisture_RAW_MAX = moisture_RAW.read()

    moisture_Average_RAW = moisture_Cumulative_RAW / 20

    moisture_PERC = (1 - (moisture_Average_RAW - moisture_RAW_MIN) / (moisture_RAW_MAX - moisture_RAW_MIN))*100
    print('Soil Moisture: ' + str(moisture_PERC) + '%')

    moisture_PWM.deinit()
    blynk.virtual_write(blynk_VPIN_Moisture, moisture_PERC)
    


    """--- Soil Temperature Sensor ---""" 
    #WHILE LOOP
    soil_temperature_RAW.convert_temp()
    sleep(0.750)
    for rom in roms:
        #print(rom)
        print("Soil Temperarture: ", soil_temperature_RAW.read_temp(rom))
    sleep(1)
    blynk.virtual_write(blynk_VPIN_Soil_Temp, soil_temperature_RAW.read_temp(rom))


    """--- Air Temperature/Humidity Sensor ---""" 
    try:
        sleep(2)
        sensor.measure()
        temp = sensor.temperature()
        hum = sensor.humidity()
        print('Air Temperature: %3.1f C' %temp)
        print('Air Humidity: %3.1f %%' %hum)
    except OSError as e:
        print('Failed to read sensor.')

    print(" ")
    blynk.virtual_write(blynk_VPIN_Air_Temp, temp)
    blynk.virtual_write(blynk_VPIN_Air_Hum, hum)

while True:
    blynk.run()
    sleep(5)

TimerError.

With a single timer with run_once==True, the second time timer.Run() is called in the main loop, I get TimerError('Running timers not found').

Here's the pertinent code:

import blynktimer
timer = blynktimer.Timer()

@timer.register(interval = 5, run_once = True)
def timeronce():
  print('timer once')
try:
  while True:
    blynk.run()
    timer.run()
except KeyboardInterrupt:
  blynk.disconnect()
  print('Blynk interrupted by YOU!')

And the print outs:

timer once
Traceback (most recent call last):
  File "BlynkClient.py", line 105, in <module>
    timer.run()
  File "C:\Users\xxx\AppData\Local\Programs\Python\Python38\lib\site-packages\blynktimer.py", line 104, in run
    raise TimerError('Running timers not found')
blynktimer.TimerError: Running timers not found

Blynk just sync last pin

When I try to use more than one pin, only the last pin receive the command. For example, I was trying to use the Raspberry pi 3 GPIO pins 29, 31,33,36,35, 38, 40 and 37. I mapped this buttons on the app with virtual pin configuration, when I pressed the button binded to pin 29 the GPIO 37 turn on. The same occurs to every button on the app, just the GPIO 37 respond.

Here is my code:

import blynklib
import RPi.GPIO as GPIO

BLYNK_AUTH = ''

blynk = blynklib.Blynk(BLYNK_AUTH)

R_1 = 29
R_2 = 31
R_3 = 33
R_4 = 36
R_5 = 35
R_6 = 38
R_7 = 40
R_8 = 37

gpioList = [R_1,R_2,R_3,R_4,R_5,R_6,R_7,R_8]

OFF = GPIO.HIGH
ON = GPIO.LOW

colors = {ON : '#FFC300', OFF : '#CCCCCC', 'OFFLINE': '#FF0000'}

GPIO.setmode(GPIO.BOARD)

for i in gpioList:
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, OFF)
    print('Cleanning up pins {}'.format(i))

@blynk.handle_event('write V{}'.format(R_1))
def read_handler_r_1(pin, value):
    print('\nHandler 1')
    do_button_action(pin, value)

@blynk.handle_event('write V{}'.format(R_2))
def read_handler_r_2(pin, value):
    print('\nHandler 2')
    do_button_action(pin, value)

@blynk.handle_event('write V{}'.format(R_3))
def read_handler_r_3(pin, value):
    print('\nHandler 3')
    do_button_action(pin, value)

@blynk.handle_event('write V{}'.format(R_4))
def read_handler_r_4(pin, value):
    print('\nHandler 4')
    do_button_action(pin, value)

@blynk.handle_event('write V{}'.format(R_5))
def read_handler_r_5(pin, value):
    print('\nHandler 5')
    do_button_action(pin, value)

@blynk.handle_event('write V{}'.format(R_6))
def read_handler_r_6(pin, value):
    print('\nHandler 6')
    do_button_action(pin, value)

@blynk.handle_event('write V{}'.format(R_7))
def read_handler_r_7(pin, value):
    print('\nHandler 7')
    do_button_action(pin, value)

@blynk.handle_event('write V{}'.format(R_8))
def read_handler_r_8(pin, value):
    print('\nHandler 8')
    do_button_action(pin, value)


def do_button_action(pin, value):
    print('pin: {}  value:{}'.format(pin, value[0]))
    button_state = value[0]
    pin_state = GPIO.input(pin)
    print('The current pin value is: {}'.format(pin_state))
    if int(button_state) == OFF:
        GPIO.output(i, ON)
        blynk.virtual_write(pin, button_state)
        blynk.set_property(pin, 'color', colors[OFF])
        print('The pin {} is on!'.format(pin))
    else:
        GPIO.output(i, OFF)
        blynk.virtual_write(pin, button_state)
        blynk.set_property(pin, 'color', colors[OFF])
        print('The pin {} is off!'.format(pin))

@blynk.handle_event("connect")
def connect_handler():
    for pin in gpioList:
        print('Syncing virtual pin {}'.format(pin))
        current_state = 0 if GPIO.input(pin) else 1
        blynk.virtual_write(pin, current_state)
        blynk.set_property(pin, 'color', colors[current_state])
        blynk.read_response(timeout=0.5)

@blynk.handle_event("disconnect")
def disconnect_handler():
    for pin in gpioList:
        print("Set 'OFFLINE' color for pin {}".format(pin))
        blynk.set_property(pin, 'color', colors['OFFLINE'])
        current_state = 0 if GPIO.input(pin) else 1
        blynk.virtual_write(pin, current_state)

try:
    while True:
        blynk.run()
except KeyboardInterrupt:
    blynk.disconnect()
    print("Blynk disconnected!")
finally:
    GPIO.cleanup()
    print("Pins reseted!")

Is Somebody pass throught this issue too ?
Thanks in advance.

handle_event with VirtualPin V0 doesn't work

starting from example 01_write_virtual_pin.py,
I designed an app with 8 button and i assigned for each
button a virtual pin (starting from V0 to V7)

I set up an handler for each 'write' event, i.e for V0:

@blynk.handle_event('write V0')
def write_virtual_pin_handler(pin, value):
    print(WRITE_EVENT_PRINT_MSG.format(pin, value))

the script works for all virtual pin except V0.
Then I tried with wilcard:

@blynk.handle_event('write V*')
def write_virtual_pin_handler(pin, value):
    print(WRITE_EVENT_PRINT_MSG.format(pin, value))

and again the script works for all virtual pin except V0.

an error in blynktimer.py

######## when I am running the basic example in TIMERS.md ######
from blynktimer import Timer
blynk_timer = Timer()

@blynk_timer.register(interval=1, run_once=True)
def your_run_once_function():
print('Hello, World!')

@blynk_timer.register(interval=5)
def your_periodical_function():
print('Hello, Blynkers!')

while True:
blynk_timer.run()

######## it raises error as below ########
mpython soft reboot
Traceback (most recent call last):
File "main.py", line 5, in
File "blynktimer.py", line 37, in init
TypeError: object of type 'dict_view' has no len()
MicroPython v1.3.0-11-g537a05c on 2019-04-08; mPython with ESP32
Type "help()" for more information.

Catching generic button events possible?

Hi,
I am writing a python script that deals with a changing number of buttons on the Blynk app side.
Currently every button event is caught individually:

@blynk.handle_event('write V1')
def write_virtual_pin_handler1(pin, value):
...

@blynk.handle_event('write V3')
def write_virtual_pin_handler3(pin, value):
...

Is there a way to catch all or a subset of buttons via same method? Since pin is available I can make determination which event happened?
Like this for instance?

@blynk.handle_event('write V*')
def write_virtual_pin_handler_all(pin, value):
...

Terminal is not updated

I am writing to the the pin connected to terminal as per the example given but I am not getting any details on Blynk terminal screen.

@blynk.handle_event("connect")
def connect_handler():
        header = ''
        result = ''
        delimiter = '{}\n'.format('=' * 30)
        # write details of device to terminal
        for command in DEVICE_COMMANDS:
                try:
                        result = subprocess.check_output(command).decode('utf-8')
                        header = '[output]\n'
                except Exception as err:
                        header = '[error]\n'
                        result = 'Return code: {}\n'.format(err)
                if result:
                        output = '{}{}{}{}'.format(header, delimiter, result, delimiter)
                        print(output)
                        blynk.virtual_write(TERMINAL_PIN, output)
                        blynk.virtual_write(TERMINAL_PIN, '\n')

Am I doing anything wrong ? or is it an issue in library?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.