Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reconnect after loss signal. #36

Open
FishermanJ opened this issue Apr 6, 2019 · 16 comments
Open

Reconnect after loss signal. #36

FishermanJ opened this issue Apr 6, 2019 · 16 comments

Comments

@FishermanJ
Copy link

Hello

I cannot understand how to use this library working all the time.. When I loss signal its show me the error: BlynkLib.py line 240, in _write. and similar problems.. I do not know how to reconnect blynk correctly after loosing signal.. There is some hidden code which connect into the wifi automaticly, however Im not able to reconnect blynk because I got similar error.

Im using ESP8266 with micropython build.

@BradenM
Copy link
Contributor

BradenM commented Apr 6, 2019

@FishermanJ,

Probably the simplest way to reattempt a connection until success is by using a try/catch block like so:

 def connect_blynk():
    '''Connects to Blynk Server'''
    try:
        blynk = BlynkLib.Blynk(auth)
    except Exception as e:
        print("Failed to connect to Blynk, trying again...")
        connect_blynk()
    print("Connected to Blynk Server")
    return blynk

As for reconnecting to wireless, that is not "hidden code" so to speak, but is actually the esp8266 firmware that automatically reconnects to the previously connected network upon boot. An easy way to handle this is to make use of the .isconnected() method provided by the network.WLAN class.

For example:

wifi = network.WLAN(network.STA_IF)
if wifi.isconnected():
    print("Connected to WiFi")
    return wifi
print("Connecting to Wifi...")
wifi.active(True)
wifi.connect(ssid, password)
while not wifi.isconnected():
   pass
print("Wifi Connected")
return wifi

It has been a minute since I worked with an esp8266 with the BlynkLibrary, but I do remember there being a possible issue when trying to connect to Blynk if the esp automatically reconnected to wifi. I believe I just forced the esp to disconnect and reconnect before attempting the Blynk connection as a quick workaround, something like so:

def wifi_connect():
    wifi = network.WLAN(network.STA_IF)
    if wifi.isconnected():
       wifi.disconnect()
       return wifi_connect()
  ...the rest of the connect code, followed by attempting to connect to Blynk

This was referenced Jun 28, 2021
@Tarun75
Copy link

Tarun75 commented Jul 18, 2021

Please provide details for above code, I am still not able to handle disconnection of wifi.

@Tarun75
Copy link

Tarun75 commented Sep 11, 2021

@vshymanskyy Still no response, please help as I have tried all the options to handle disconnect of wifi , but seems difficult. I expect prompt support from Blynk team for potential customers.

@vshymanskyy
Copy link
Owner

For esp8266, we recommend using Arduino for potential customers. ESP8266 lacks resources to run a complex, micropython-based IoT project

@Tarun75
Copy link

Tarun75 commented Sep 11, 2021

@vshymanskyy , Hi Thanks for response, but is that the case for ESP32 as well.

@BradenM
Copy link
Contributor

BradenM commented Sep 11, 2021

@Tarun75
Sorry, I never saw your initial reply.

Please provide details for above code

Which part of the code I provided would you like details for?

@andypnz
Copy link

andypnz commented Jun 9, 2023

Hi. Using Blynk, Micropython and asyncio on a RP2040. My app works fine without Blynk - but Blynk would be a nice addition - but it is important the app keeps working without it. My app normally does not require a WiFi connection. I am trying to implement code to handle:

  1. Blynk server connection fails
  2. Wifi not available on boot, but then is later
  3. Wifi connection drops out, and then potentially comes back
  4. Wifi remains connected, but internet drops out or was not present - and then potentially returns

Below is a simplified version of my app - but if I can get the above working here, it will also work in my full app.

@BradenM I am afraid I am at a loss to implement your suggestions at the start of this post - are you able to look at my code and offer some guidance? Thank you!

import utime
import network
import BlynkLib
import uasyncio

blynk_connection = False
 
voltpin = ADC(Pin(26))
readDelay = 2
 
BLYNK_AUTH = "my_token"
ssid = "test"
password = "123456" 
 
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
       
wait = 10
while wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    wait -= 1
    print('waiting for connection...')
    utime.sleep(1)
 
# Handle connection error
if wlan.status() != 3:
    raise RuntimeError('wifi connection failed')
else:
    print('connected')
    ip=wlan.ifconfig()[0]
    print('IP: ', ip)
 
blynk = BlynkLib.Blynk(BLYNK_AUTH)

async def read_voltage():
  while True:
    voltage = voltpin.read_u16() / 1000
    print("voltage: " + "%.2f" % voltage +" (adc: "+str(voltpin.read_u16())+")")
    if (blynk_connection == True):
        print("Blynk Connected True")
        blynk.virtual_write(4, voltage)
    else:
        print("no blynk connection")
    await uasyncio.sleep_ms(500)

def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)

@blynk.on("V0")
def v5_write_handler(value):
    print('Requested water heater state: {}'.format(value[0]))
      
@blynk.on("V5")
def v5_write_handler(value):
    print('requested room heater state: {}'.format(value[0]))

@blynk.on("connected")
def blynk_connected(ping):
    global blynk_connection
    blynk_connection = True
    print('Blynk ready. Ping:', ping, 'ms')

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

async def main():
    set_global_exception()
    uasyncio.create_task(read_voltage())
    await blynk.run()
try:
    uasyncio.run(main())
finally:
    uasyncio.new_event_loop()    

@ebolisa
Copy link

ebolisa commented Jun 9, 2023

My app normally does not require a WiFi connection. I am trying to implement code to handle:

Try this:

# Initialize Blynk
try:
#     blynk = BlynkLib.Blynk(BLYNK_AUTH) # faster
    
#      or....

    blynk = BlynkLib.Blynk(BLYNK_AUTH,
        insecure=True,          	# disable SSL/TLS
        server='lon1.blynk.cloud',	# lon1 fra1.blynk.cloud, blynk.cloud or your local blynk server
        port=80,                	# set server port
        heartbeat=30, 				# set heartbeat to 30 secs      
        log=print              	# use print function for debug logging
        )
except OSError as e:
    print('ERROR', e)
    # restart_and_reconnect(e)

As for the wifi issue, try to add this:

from usys import platform

ESP32 = platform == 'esp32' or platform == 'esp32_LoBo'
RP2 = platform == 'rp2'
ESP8266 = platform == 'esp8266'

# ---
if RP2:
    rp2.country('ES') < --- change this for your local settings
    wlan.config(pm = 0xa11140) # turn off power savings
wlan.connect(ssid, password)

I have not reviewed the rest of your code.
Good luck!

@andypnz
Copy link

andypnz commented Jun 9, 2023

Thank you! I tried incorporating your suggestions (as below), and I tested these two situations. Any help how to proceed really appreciated - I am sure this will also help others using Blynk with micropython :-)

  1. With wif network turned off I get this on boot:
Traceback (most recent call last):
  File "<stdin>", line 41, in <module>
RuntimeError: wifi connection failed

What can I do here to occasionally re-try the connection but continue with the rest of the code in the meantime?

  1. If I turn off my wifi AP once connected, the log output keeps going for a while as if it is still connected (not much of a problem - but interesting):
Blynk Connected True
< 20 172 | vw 4 12.034
voltage: 10.26 (adc: 10850)
Blynk Connected True
< 20 173 | vw 4 10.258
etc

This keeps going for a minute or two, then eventually errors out:

Blynk Connected True
< 20 320 | vw 4 11.602
Traceback (most recent call last):
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 71, in read_voltage
  File "BlynkLib.py", line 86, in virtual_write
  File "BlynkLib.py", line 119, in _send
  File "BlynkLib.py", line 251, in _write
OSError: [Errno 113] EHOSTUNREACH

Once it errors out, how can I occasionally keep trying to connect, but in the meantime continue with the rest of the code?

My code with your suggestions added:

import utime
import network
import BlynkLib
import uasyncio
from usys import platform

RP2 = platform == 'rp2'

blynk_connection = False
 
voltpin = ADC(Pin(26))
readDelay = 2
 
BLYNK_AUTH = "my_token"
ssid = "test"
password = "1234"
 
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

if RP2:
    rp2.country('NZ') 
    wlan.config(pm = 0xa11140) # turn off power savings

    wlan.connect(ssid, password)
       
wait = 10
while wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    wait -= 1
    print('waiting for connection...')
    utime.sleep(1)
 
# Handle connection error
if wlan.status() != 3:
    raise RuntimeError('wifi connection failed')
else:
    print('connected')
    ip=wlan.ifconfig()[0]
    print('IP: ', ip)
 
#blynk = BlynkLib.Blynk(BLYNK_AUTH)
    
def R1_timeout(): green_led(False)
# Initialize Blynk
try:
#     blynk = BlynkLib.Blynk(BLYNK_AUTH) # faster   
#      or....
    blynk = BlynkLib.Blynk(BLYNK_AUTH,
        insecure=True,         
        server='lon1.blynk.cloud',  # lon1 fra1.blynk.cloud, blynk.cloud or your local blynk server
        port=80,             
        heartbeat=30,      
        log=print
        )
except OSError as e:
    print('ERROR', e)
    #restart_and_reconnect(e)    
    
async def read_voltage():
  while True:
    voltage = voltpin.read_u16() / 1000
    print("voltage: " + "%.2f" % voltage +" (adc: "+str(voltpin.read_u16())+")")
    if (blynk_connection == True):
        print("Blynk Connected True")
        blynk.virtual_write(4, voltage)
    else:
        print("no blynk connection")
    await uasyncio.sleep_ms(500)

def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)

@blynk.on("V0")
def v5_write_handler(value):
    print('Requested water heater state: {}'.format(value[0]))
      
@blynk.on("V5")
def v5_write_handler(value):
    print('requested room heater state: {}'.format(value[0]))

@blynk.on("connected")
def blynk_connected(ping):
    global blynk_connection
    blynk_connection = True
    print('Blynk ready. Ping:', ping, 'ms')

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

async def main():
    set_global_exception()
    uasyncio.create_task(read_voltage())
    await blynk.run()
try:
    uasyncio.run(main())
finally:
    uasyncio.new_event_loop()    

Thank you!

@ebolisa
Copy link

ebolisa commented Jun 9, 2023

I cannot test your code as I’m away from my PC throughout this weekend but, I’m surprised the code compiles as you added the ‘R1_timeout’ function which is not needed (I edited my post).
as for the wifi, why don’t you check your wifi connection in a loop?
Some like…

If wlan.isconnected():
   ‘do things here
else:
   connect()

Where

wlan = network.WLAN(network.STA_IF)
def connect():
   global wlan
   ‘put all your wifi connections here

Try to organize better the code 😉

@andypnz
Copy link

andypnz commented Jun 9, 2023

Hi... Thanks again.... would be really appreciated if you could have a look sometime when you are in front of a PC....

I have edited this post - I had an indent issue - this code runs. But if I turn off the wifi I get this error after a minute or so..... and other disconnect or no wifi scenarios fail as well....

The Blynk write_handler() fails with:

Blynk Connected True
< 20 857 | vw 4 10.45
voltage: 11.65 (adc: 12851)
Blynk Connected True
< 20 858 | vw 4 11.65
Traceback (most recent call last):
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 73, in read_voltage
  File "BlynkLib.py", line 86, in virtual_write
  File "BlynkLib.py", line 119, in _send
  File "BlynkLib.py", line 251, in _write
OSError: [Errno 113] EHOSTUNREACH

Current code:

from machine import ADC, Pin
import utime
import network
import BlynkLib
import uasyncio
from usys import platform

RP2 = platform == 'rp2'
blynk_connection = False
 
voltpin = ADC(Pin(26))
readDelay = 2
 
BLYNK_AUTH = "my_token"
ssid = "Test"
password = "1234"
 
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

async def connect():
    print("connect loop running")
    await uasyncio.sleep_ms(1000)
    global wlan
    global blynk
    if RP2:
        rp2.country('NZ') 
        wlan.config(pm = 0xa11140) # turn off power savings
        wlan.connect(ssid, password)      
    wait = 10
    while wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        wait -= 1
        print('waiting for connection...')
        await uasyncio.sleep_ms(10)
    if wlan.status() != 3:
        await uasyncio.sleep_ms(2000)
        connect()
        #raise RuntimeError('wifi connection failed')
    else:
        print('connected')
        ip=wlan.ifconfig()[0]
        print('IP: ', ip) 
        # Initialize Blynk
try:
#     blynk = BlynkLib.Blynk(BLYNK_AUTH) # faster
#      or....
    blynk = BlynkLib.Blynk(BLYNK_AUTH,
        insecure=True,         
        server='lon1.blynk.cloud',   # lon1 fra1.blynk.cloud, blynk.cloud or your local blynk server
        port=80, 
        heartbeat=30,    
        log=print       
        )
except OSError as e:
    print('ERROR', e)
    # restart_and_reconnect(e)   

async def read_voltage():
  while True:
    voltage = voltpin.read_u16() / 1000
    print("voltage: " + "%.2f" % voltage +" (adc: "+str(voltpin.read_u16())+")")
    if (blynk_connection == True):
        print("Blynk Connected True")
        blynk.virtual_write(4, voltage)
    else:
        print("no blynk connection")
    await uasyncio.sleep_ms(500)

def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)

@blynk.on("V0")
def v5_write_handler(value):
    print('Requested water heater state: {}'.format(value[0]))
      
@blynk.on("V5")
def v5_write_handler(value):
    print('requested room heater state: {}'.format(value[0]))

@blynk.on("connected")
def blynk_connected(ping):
    global blynk_connection
    blynk_connection = True
    print('Blynk ready. Ping:', ping, 'ms')

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

async def main():
    global blynk
    set_global_exception()
    uasyncio.create_task(connect())
    uasyncio.create_task(read_voltage())
    await blynk.run()
try:
    uasyncio.run(main())
finally:
    uasyncio.new_event_loop()    

@ebolisa
Copy link

ebolisa commented Jun 10, 2023

Hi,
I didn't review your whole code but I did modify your connection to Blynk.
In python it's important to pay attention to spaces.
The following code runs but only once. You need to decide what is needed to loop.
I used a Pico W board to test it.

from machine import ADC, Pin
import utime
import network
import BlynkLib
import uasyncio
from usys import platform
import gc
gc.collect()

RP2 = platform == 'rp2'
blynk_connection = False
 
voltpin = ADC(Pin(26))
readDelay = 2
 
BLYNK_AUTH = "----l"
ssid = "-----"
password = "-------"

global blynk
 
wlan = network.WLAN(network.STA_IF)

async def connect():
    print("connect loop running")
    await uasyncio.sleep_ms(1000)
    global wlan
    global blynk
    
    wlan.active(True)
    if RP2:
        rp2.country('NZ') 
        wlan.config(pm = 0xa11140) # turn off power savings
        
    wlan.connect(ssid, password)
    wait = 10
    
    while wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        wait -= 1
        print('waiting for connection...')
        await uasyncio.sleep_ms(10)
        
    if wlan.status() != 3:
        await uasyncio.sleep_ms(2000)
        return False
#         connect()
        #raise RuntimeError('wifi connection failed')
    else:
        print('connected')
        ip=wlan.ifconfig()[0]
        print('IP: ', ip)
        
        return True
    
if connect():
    # Initialize Blynk
    try:
    #     blynk = BlynkLib.Blynk(BLYNK_AUTH) # faster
    #      or....
        blynk = BlynkLib.Blynk(BLYNK_AUTH,
                               insecure=True,
                               server='lon1.blynk.cloud',   # lon1 fra1.blynk.cloud, blynk.cloud or your local blynk server
                               port=80,
                               heartbeat=30,
                               log=print
                               )
    except OSError as e:
        print('ERROR', e)
else:
    print('unable to connect to network')
    

async def read_voltage():
  while True:
    voltage = voltpin.read_u16() / 1000
    print("voltage: " + "%.2f" % voltage +" (adc: "+str(voltpin.read_u16())+")")
    if (blynk_connection == True):
        print("Blynk Connected True")
        blynk.virtual_write(4, voltage)
    else:
        print("no blynk connection")
    await uasyncio.sleep_ms(500)
    

def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)
    

@blynk.on("V0")
def v5_write_handler(value):
    print('Requested water heater state: {}'.format(value[0]))
      
@blynk.on("V5")
def v5_write_handler(value):
    print('requested room heater state: {}'.format(value[0]))

@blynk.on("connected")
def blynk_connected(ping):
    global blynk_connection
    blynk_connection = True
    print('Blynk ready. Ping:', ping, 'ms')

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

async def main():
    gc.collect()
    set_global_exception()
    uasyncio.create_task(connect())
    uasyncio.create_task(read_voltage())
    print('Am I in a loop?')
    #await blynk.run()
    
    
try:
    uasyncio.run(main())
finally:
   uasyncio.new_event_loop()  

output:

>>> %Run -c $EDITOR_CONTENT

    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ for Python v1.0.0 (rp2)

Connecting to lon1.blynk.cloud:80...
< 29 1 | ---------------------
Am I in a loop?
>>>

@andypnz
Copy link

andypnz commented Jun 11, 2023

Thank you!

I think the simplest solution to what I am trying to achieve is to run the async connect() loop anytime there is no wifi network, no wifi connection or no internet / Blynk connection. So long as I have a flag blynk_connection = True / False, I think this is workable.

So if I connect to a wifi with internet all is good.
If I unplug the WAN from the AP providing the wifi + internet it continues to report 'Blynk Connected True' for maybe a minute. Then eventually it errors out with this:

< 20 307 | vw 4 11.25
voltage: 13.54 (adc: 13795)
Blynk Connected True
< 20 308 | vw 4 13.539
voltage: 11.83 (adc: 11970)
Blynk Connected True
< 20 309 | vw 4 11.826
voltage: 10.90 (adc: 11442)
Blynk Connected True
< 20 310 | vw 4 10.898
Traceback (most recent call last):
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 80, in read_voltage
  File "BlynkLib.py", line 86, in virtual_write
  File "BlynkLib.py", line 119, in _send
  File "BlynkLib.py", line 251, in _write
OSError: [Errno 113] EHOSTUNREACH

This check seems to never be triggered:

@blynk.on("disconnected")
def blynk_disconnected():
    blynk_connection = False
    print('Blynk disconnected')

This is the current code, including starting to think about restarting the connect() loop if there is no Blynk connection:

from machine import ADC, Pin
import utime
import network
import BlynkLib
import uasyncio
from usys import platform
import gc
from details import BLYNK_AUTH, ssid, password 
gc.collect()

RP2 = platform == 'rp2'
blynk_connection = False
 
voltpin = ADC(Pin(26))
readDelay = 2

global blynk
global f
 
wlan = network.WLAN(network.STA_IF)

async def connect():
    print("connect loop running")
    await uasyncio.sleep_ms(1000)
    global wlan
    global blynk
    
    wlan.active(True)
    if RP2:
        rp2.country('NZ') 
        wlan.config(pm = 0xa11140) # turn off power savings
        
    wlan.connect(ssid, password)
    wait = 10
    
    while wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        wait -= 1
        print('Waiting for connection...')
        await uasyncio.sleep_ms(10)
        
    if wlan.status() != 3:
        await uasyncio.sleep_ms(2000)
        return False
#         connect()
        #raise RuntimeError('wifi connection failed')
    else:
        print('Connected to', ssid, " WiFi")
        ip=wlan.ifconfig()[0]
        print(ssid, ' IP: ', ip)
        return True
    
if connect():
    #global f
    # Initialize Blynk
    try:
    #     blynk = BlynkLib.Blynk(BLYNK_AUTH) # faster
    #      or....
        blynk = BlynkLib.Blynk(BLYNK_AUTH,
                               insecure=True,
                               server='lon1.blynk.cloud',   # lon1 fra1.blynk.cloud, blynk.cloud or your local blynk server
                               port=80,
                               heartbeat=30,
                               log=print
                               )
    except OSError as e:
        print('ERROR', e)
        #restart_f()
        
else:
    print('unable to connect to network')
    

async def read_voltage():
  global f
  while True:
    voltage = voltpin.read_u16() / 1000
    print("voltage: " + "%.2f" % voltage +" (adc: "+str(voltpin.read_u16())+")")
    if (blynk_connection == True):
        print("Blynk Connected True")
        blynk.virtual_write(4, voltage)
    else:
        print("no blynk connection, so restart wifi connection")
        f.cancel()
        await uasyncio.sleep(0.1)
        f=uasyncio.create_task(connect())  
    await uasyncio.sleep_ms(500)
    

def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)
    

@blynk.on("V0")
def v5_write_handler(value):
    print('Requested water heater state: {}'.format(value[0]))
      
@blynk.on("V5")
def v5_write_handler(value):
    print('requested room heater state: {}'.format(value[0]))

@blynk.on("connected")
def blynk_connected(ping):
    global blynk_connection
    blynk_connection = True
    print('Blynk ready. Ping:', ping, 'ms')

@blynk.on("disconnected")
def blynk_disconnected():
    blynk_connection = False
    print('Blynk disconnected')

#def restart_f():
#    global f
#    f.cancel()
#    await uasyncio.sleep(0.1)
#    f = uasyncio.create_task(connect())

async def main():
    global f
    gc.collect()
    set_global_exception()
    f = uasyncio.create_task(connect())
    g = uasyncio.create_task(read_voltage())
    print('Am I in a loop?')
    await blynk.run()
    
try:
    uasyncio.run(main())
finally:
    uasyncio.new_event_loop()  

Additionally, sometimes during testing I get this error - happens with no changes to the code - and seems to require Thonny restarted, RP2040 power cycled, and a few goes to eliminate. Notice it does not start with 'connect loop running':


    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ for Python v1.0.0 (rp2)

Connecting to lon1.blynk.cloud:80...
ERROR -6
Traceback (most recent call last):
  File "<stdin>", line 100, in <module>
NameError: name 'blynk' isn't defined

@ebolisa
Copy link

ebolisa commented Jun 11, 2023

As I said, I didn't check your whole code, I just wanted to show you how to connect to Blynk with mpython.

I don't use uasyncio with Blynk but, I do know the lib works as I'm using it 14/7 with a mqtt server connection.

As for "ERROR -6", it means that your devise has no connections to the router/internet thus connect() returns False --> "name 'blynk' isn't defined".

I remind you, Blynk doesn't like delays within a loop. Probably this' what's causing your problem.

My suggestion:

Make Blynk work without uasyncio.
Use conditional statements to check often your wifi connection.
For testing purpose, keep the devise close to the router.
Try with a second device if you have an extra one.
Use a very basic code to ensure you have a solid connection first like the one shown below.
Once you achieved a solid connection, add more code lines.

import utime
import network
import BlynkLib
from BlynkTimer import BlynkTimer
from usys import platform
import gc
gc.collect()

RP2 = platform == 'rp2'
BLYNK_AUTH = "-------"
ssid = "--------"
password = "-------"
wlan = network.WLAN(network.STA_IF)

timer = BlynkTimer()

def restart_and_reconnect(reason):
    print('Some went wrong. Reconnecting...')
    print('Due to ', reason)
    utime.sleep(5)
    from umachine import reset
    reset()


print("Connecting to router")

wlan.active(True)
utime.sleep_ms(200)
    
if RP2: # may want to comment this out as a test
    rp2.country('NZ') 
    wlan.config(pm = 0xa11140) # turn off power savings
    
if not wlan.isconnected():
    wlan.connect(ssid, password)
    utime.sleep_ms(200)
    while not wlan.isconnected():
        pass
else:
    print("Network config:", wlan.ifconfig())
 

print("Initializing Blynk")
try:
    #     blynk = BlynkLib.Blynk(BLYNK_AUTH) # faster
    #      or....
    blynk = BlynkLib.Blynk(BLYNK_AUTH,
                           insecure=True,
                           server='lon1.blynk.cloud',   # lon1 fra1.blynk.cloud, blynk.cloud or your local blynk server
                           port=80,
                           heartbeat=30,
                           log=print
                           )
except OSError as e:
    restart_and_reconnect('Blynk server failure. Error:' + str(e))
    

@blynk.on("connected")
def blynk_connected(ping):
    print('Blynk ready. Ping:', ping, 'ms')
    blynk.sync_virtual()
    

@blynk.on("disconnected")
def blynk_disconnected():
    print('Blynk disconnected')
    utime.sleep(5)
    restart_and_reconnect('Blynk server failure...')
    
    
# Let's send an update to virtual pin 0 on the Blynk's app
def uptime():
    gc.collect()
    uptime = 'Uptime in seconds: ' + str(utime.ticks_ms() // 1000)
    blynk.virtual_write(0, uptime)
    

def loop():
    while True:
        blynk.run()
        timer.run()
        
timer.set_interval(1, uptime)
        
loop()

output:

MicroPython v1.19.1-821-g3b5cafc71 on 2023-01-19; Raspberry Pi Pico W with RP2040
MPY: soft reboot

    ___  __          __
   / _ )/ /_ _____  / /__
  / _  / / // / _ \/  '_/
 /____/_/\_, /_//_/_/\_\
        /___/ for Python v1.0.0 (rp2)

Connecting to router
Network config: ('192.168.1.26', '255.255.255.0', '192.168.1.1', '192.168.1.1')
Initializing Blynk
Connecting to lon1.blynk.cloud:80...
< 29 1 | --------
> 0 1 | 200
< 17 2 | ver 1.0.0 h-beat 30 buff-in 1024 dev rp2-py
Blynk ready. Ping: 542 ms
< 16 3 | vr
> 0 2 | 200
> 0 3 | 2
< 20 4 | vw 0 Uptime in seconds: 152
< 20 5 | vw 0 Uptime in seconds: 153
< 20 6 | vw 0 Uptime in seconds: 154
< 20 7 | vw 0 Uptime in seconds: 155
< 20 8 | vw 0 Uptime in seconds: 156
< 20 9 | vw 0 Uptime in seconds: 157

@andypnz
Copy link

andypnz commented Jun 11, 2023

Thanks again. I have had it generally working without asyncio.... but asyncio is a key to this project..... And I should have been clear that it was working with asyncio if I had a stable WiFi connection - I am trying to solve lack of wifi / internet / Blynk connection and still have the rest of the app continue running normally and automatically try reconnecting - sorry about that!

The below code almost(?) works. If I remove the Blynk write_handlers and don't use blynk.virtual_write either - it restarts the wifi + Blynk etc.

First problem is blynk.run() is not available - or rather I think it runs, but is not usable..... so blynk.virtual_write does not work.

Second problem is getting the write_handlers working - once 'blynk_final_ready == True'. Obviously what I currently have does not work as it is only runs once (and the condition is false) - but I cant see a method of running these once 'blynk_final_ready == True'. I tried putting them inside a function, and that did not seem to work..... any idea how I can run (or activate) these conditionally? But I guess they need blynk.run() working first.....

But I think the bigger issue is blynk.run() not correctly running (or is not usable after it runs?)

if (blynk_final_ready == True):
 print("Do this stuff")   
 @blynk.on("V0")
 def v5_write_handler(value):
    print('Requested water heater state: {}'.format(value[0]))
 @blynk.on("V5")
 def v5_write_handler(value):
    print('requested room heater state: {}'.format(value[0]))
etc.......
import utime
import network
import BlynkLib
import uasyncio
from usys import platform
import gc
from details import BLYNK_AUTH, ssid, password 
gc.collect()

RP2 = platform == 'rp2'
blynk_connection = False
blynk_final_ready = False
connected_wifi = False
 
voltpin = ADC(Pin(26))
readDelay = 2

global blynk
global f
global h
 
wlan = network.WLAN(network.STA_IF)

async def connect():
    await uasyncio.sleep(1)
    print("connect loop running")
    await uasyncio.sleep_ms(1000)
    global wlan
    global blynk
    global connected_wifi
    global h
    
    wlan.active(True)
    if RP2:
        rp2.country('NZ') 
        wlan.config(pm = 0xa11140) # turn off power savings
        
    wlan.connect(ssid, password)
    wait = 10
    
    while wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        wait -= 1
        print('Waiting for connection...')
        await uasyncio.sleep_ms(10)
        
    if wlan.status() != 3:
        await uasyncio.sleep_ms(2000)
        return False
    else:
        print('Connected to', ssid, " WiFi")
        ip=wlan.ifconfig()[0]
        print(ssid, ' IP: ', ip)
        connected_wifi = True
        h = uasyncio.create_task(bconnect())
        return True

def restart_f():
    global f
    f.cancel()
    await uasyncio.sleep(0.1)
    f = uasyncio.create_task(connect())
    
async def bconnect():
    print("here ALREADY!!")
    await uasyncio.sleep(1)
    global f
    global blynk_connection
    global blynk
    # Initialize Blynk
    try:
        #blynk = BlynkLib.Blynk(BLYNK_AUTH) # faster
    #      or....
        blynk = BlynkLib.Blynk(BLYNK_AUTH,
                               insecure=True,
                               server='lon1.blynk.cloud',   # lon1 fra1.blynk.cloud, blynk.cloud or your local blynk server
                               port=80,
                               heartbeat=30,
                               log=print
                               )
        blynk_connection = True
        print("Blynk connection: ", blynk_connection)
    except OSError as e:
        print('ERROR', e)
        blynk_connection = False
        restart_f()

async def read_voltage():
  global f
  global h
  global i
  global blynk_final_ready
  global connected_wifi
  global blynk_connection
  await uasyncio.sleep(20)
  while True:
    voltage = voltpin.read_u16() / 1000
    print("voltage: " + "%.2f" % voltage +" (adc: "+str(voltpin.read_u16())+")")
    if (blynk_final_ready == True):
        print("Blynk Connected True")
        blynk.virtual_write(4, voltage)
    elif (blynk_connection == False and connected_wifi == True):
        print("wifi ok, no blynk connection, so restart blynk")
        h.cancel()
        await uasyncio.sleep(0.1)
        h=uasyncio.create_task(bconnect())
        await uasyncio.sleep(5)

    elif (blynk_connection == False and connected_wifi == False):
        print("no blynk connection, so restart wifi connection and blynk")
        f.cancel()
        await uasyncio.sleep(0.1)
        f=uasyncio.create_task(connect())
        await uasyncio.sleep(5)
    else:
        print("Blynk Final NOT ready")
        await uasyncio.sleep(5)
        i.cancel()
        await uasyncio.sleep(0.1)        
        i=uasyncio.create_task(main())
    await uasyncio.sleep_ms(500)
    
def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)
 
if (blynk_final_ready == True):
 print("Do this stuff")   
 @blynk.on("V0")
 def v5_write_handler(value):
    print('Requested water heater state: {}'.format(value[0]))
      
 @blynk.on("V5")
 def v5_write_handler(value):
    print('requested room heater state: {}'.format(value[0]))

 @blynk.on("connected")
 def blynk_connected(ping):
    global blynk_connection
    blynk_connection = True
    print('Blynk ready. Ping:', ping, 'ms')

 @blynk.on("disconnected")
 def blynk_disconnected():
    blynk_connection = False
    print('Blynk disconnected')

else:
    print("still not done this")

async def main():
  global blynk_connection
  global blynk_final_ready
  global blynk
  gc.collect()
  set_global_exception()
  await uasyncio.sleep(0.1)
  print("main running")
  print("blynk connection: ", blynk_connection, " and blynk_final_ready", blynk_final_ready)
  if (blynk_connection == True and blynk_final_ready == False):
   uasyncio.wait_for(blynk.run(), 10)
   #await blynk.run() 
   blynk_final_ready = True

   print("Blynk final READY: ", blynk_final_ready)
   print("blynk connection: ", blynk_connection, " and blynk_final_ready", blynk_final_ready)
  
loop = uasyncio.get_event_loop()
f=uasyncio.create_task(connect())
g=uasyncio.create_task(read_voltage())
i=uasyncio.create_task(main())
loop.run_forever()

The result is close - blynk.virtual_write(4, voltage) does not work and of course the write_handler is not available....

Blynk final READY:  True
blynk connection:  True  and blynk_final_ready True
voltage: 14.24 (adc: 13779)
Blynk Connected True
< 20 2 | vw 4 14.243
voltage: 10.59 (adc: 11042)
Blynk Connected True
< 20 3 | vw 4 10.594
voltage: 10.72 (adc: 11234)
Blynk Connected True
< 20 4 | vw 4 10.722
Traceback (most recent call last):
  File "uasyncio/core.py", line 1, in run_until_complete
  File "<stdin>", line 105, in read_voltage
  File "BlynkLib.py", line 86, in virtual_write
  File "BlynkLib.py", line 119, in _send
  File "BlynkLib.py", line 251, in _write
OSError: [Errno 104] ECONNRESET

@andypnz
Copy link

andypnz commented Jun 15, 2023

I have made some progress... this code now works - I have tested with no wifi, wifi on / off / on, and internet connection on / off / on with wifi remaining connected. Peter on the micropython forum suggested a maintainer loop, which allowed me to get things going.....

But the code is terrible - and I have ended up with stuff that should be in the maintainer loop in a new loop called test_loop.

Please post back if you tidy it up to use it!

import utime
import network
import BlynkLib
import uasyncio
from usys import platform
import gc
from details2 import BLYNK_AUTH, ssid, password 
gc.collect()

RP2 = platform == 'rp2'
blynk_connected = False
blynk_final_ready = False
wifi_connected = False
 
voltpin = ADC(Pin(26))
readDelay = 2

global blynk
global f
global h
global i
 
wlan = network.WLAN(network.STA_IF)

async def test_loop():
    global wifi_connected
    global blynk_connected
    global f
    global i
    while True:
        print("Test loop running. Wifi status: ", wifi_connected, ". wlan status code: ", wlan.status()) 
        if (wifi_connected == False):
            print("Restarting wifi connection process")
            wifi_connected = True
            blynk_connected = False
            try:
                i.cancel()
            except:
                print("Could not cancel Blynk when restarting wifi")
            f.cancel()
            await uasyncio.sleep(0.1)
            f=uasyncio.create_task(maintainer())
        if (wifi_connected == True and wlan.status() != 3):
            blynk_connected = False
            try:
                i.cancel()
            except:
                print("cant cancel i")
            try:    
                f.cancel()
            except:
                print("cant cancel f")
            await uasyncio.sleep(0.1)
            f=uasyncio.create_task(maintainer())
        if (wifi_connected == True and blynk_connected == False):
            print("Restarting Blynk......")
            try:
                i.cancel()
            except:
                print("Cant cancel i")
            try:
                f.cancel()
                await uasyncio.sleep(0.1)
                f=uasyncio.create_task(maintainer())
            except:
                print("Could not restart maintainer")
        await uasyncio.sleep(5)
        
async def maintainer():
    print("Maintainer loop running")
    await uasyncio.sleep_ms(100)
    global wlan
    global blynk
    global wifi_connected
    global blynk_connected
    global i
    await uasyncio.sleep(1)   
    wlan.active(True)
    if RP2:
        rp2.country('NZ') 
        wlan.config(pm = 0xa11140) # turn off power savings  
    wlan.connect(ssid, password)
    wait = 10
    while wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        wait -= 1
        print('Waiting for wifi connection...')
        await uasyncio.sleep_ms(100)
    if wlan.status() != 3:
        await uasyncio.sleep_ms(2000)
        print('Unable to connect wifi - trying again...')
        wifi_connected = False
    else:
        print("Connected to ", ssid, " WiFi")
        ip=wlan.ifconfig()[0]
        print(ssid, ' IP: ', ip)
        wifi_connected = True
        try:
            blynk = BlynkLib.Blynk(BLYNK_AUTH)
            i=uasyncio.create_task(blynk.run())
            blynk_handlers()
        except:
            print("Maintainer Blynk exception")
            
async def read_voltage():
  global blynk_final_ready
  global wifi_connected
  global blynk_connected
  await uasyncio.sleep(0.1)
  while True:
   print("Do other stuff here in the voltage loop that does not rely on Blynk")   
   if (blynk_connected == True):
    voltage = voltpin.read_u16() / 1000
    print("Voltage: " + "%.2f" % voltage +" (adc: "+str(voltpin.read_u16())+")")
    blynk.virtual_write(4, voltage)
    await uasyncio.sleep(2)
   else:
    print("Voltage loop - awaiting Blynk connection")   
    await uasyncio.sleep(2) 

def set_global_exception():
    def handle_exception(loop, context):
        import sys
        sys.print_exception(context["exception"])
        sys.exit()
    loop = uasyncio.get_event_loop()
    loop.set_exception_handler(handle_exception)

def blynk_handlers():
    @blynk.on("V0")
    def v5_write_handler(value):
        print('Requested water heater state: {}'.format(value[0]))
  
    @blynk.on("V5")
    def v5_write_handler(value):
        print('Requested room heater state: {}'.format(value[0]))

    @blynk.on("connected")
    def blynk_connected(ping):
        global blynk_connected
        blynk_connected = True
        print('Blynk ready. Ping:', ping, 'ms')

    @blynk.on("disconnected")
    def blynk_disconnected():
        global blynk_connected
        blynk_connected = False
        print('Blynk disconnected')

loop = uasyncio.get_event_loop()
k=uasyncio.create_task(test_loop())
f=uasyncio.create_task(maintainer())
g=uasyncio.create_task(read_voltage())
loop.run_forever()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants