blynkkk / lib-python

Blynk IoT library for Python and Micropython
MIT License
237 stars 83 forks source link

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

Closed formatcla closed 5 years ago

formatcla commented 5 years ago

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()
antohaUa commented 5 years ago

Hi! During investigation I have found that server needs closing forced reading after each virtual_sync operation. Will try to inform server developers about such strange behavior. Cause you see for example now it is impossible to use virtual pin sync call for multiple pins at once (

But we can jump over the issue by adding forcing reading into connect_handler And using single pin sync request Please see new example how to do it: https://github.com/blynkkk/lib-python/blob/master/examples/09_sync_virtual_pin.py

Also pay attention that now you may use direct blynk.disconnect() call within KeyboardInterrupt Just place all needed logic into registered disconnect handler before

Thanks a lot for all these findings made by you.

Just let me know please if fix has solved the issue you have faced with.

formatcla commented 5 years ago

The fix has solved the issue, thank you.

antohaUa commented 5 years ago

Can be closed