try: except: else: not acting right at all!!


31 posts   Page 1 of 2   1, 2
by AshPowers » Sat May 06, 2017 3:09 pm
Driving me insane over here. I *cannot* figure out where I'm going wrong on this one..

The code below is (attempting) to handle a bluetooth serial connection between android phone and RPi. Devices are paired already.

With this code running on the RPi, without a connection to the phone, all is well. The RPi is just idle waiting for connection, no errors. Upon opening BlueTerm on phone and connecting, all is well. Whatever I type on the phone shows up in the RPi terminal window.

It all goes to hell when I close the connection from the phone. Bombs out on SerialException, of all things!

I do not understand for the life of me WHY this code bombs out when I disconnect. I have been hammering on this for 5 hours, seriously, with all sorts of other variations.

***** If I remove the print(BTport.read(1)) line, I can connect and disconnect without any problems at all, but that's a completely useless bit of code if I can't actually send/receive information.

What am I missing here???

Code: Select all
import serial
from serial import SerialException
BTon = 0

while 1:
    try:
        BTport = serial.Serial("/dev/rfcomm0", baudrate=9600, timeout=3.0)
        BTport.close()
    except serial.SerialException:
        BTon = 0
    else:
        BTon = 1

    if BTon == 1:
        BTport = serial.Serial("/dev/rfcomm0", baudrate=9600, timeout=3.0)
        print(BTport.read(1))
        BTport.close()
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by davef21370 » Sat May 06, 2017 3:27 pm
When you say "bombs out" what do you mean? Is your try/except catching the error or is your code crashing and Python throwing an error?

Dave.
Apple say... Monkey do !!
User avatar
Posts: 854
Joined: Fri Sep 21, 2012 4:13 pm
Location: Earth But Not Grounded
by AshPowers » Sat May 06, 2017 3:46 pm
Hi Dave!

"Bombs out" as in Python throws the SerialException error and closes the program. That's what is driving me nuts as my code is specifically checking for that very exception. When I disconnect, it is as if this section of code has stopped working and it just tries to read from a port that cannot be opened.
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by Douglas6 » Sat May 06, 2017 4:00 pm
Just a guess. The read is throwing an exception when the serial port goes away. The read is outside of the try-catch block. Looking at the error will tell you what line it is occurring on.

You seem to be making a connection for each byte read. That's a little inefficient.
User avatar
Posts: 3872
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL
by AshPowers » Sat May 06, 2017 4:15 pm
Hi Douglas!
Thanks for the reply! This is not the full code or how I will be handling data between the two devices. This is just a small program I put together to handle *just* the connection. I plan to expand from it to handle the data in a lot more efficient manner as you pointed out. :) I am just trying to get this section working first before I move forward.

The read is outside of the try loop, yes, however, I am controlling whether or not the read loop is initiated or not through setting the value of BTon. If BTon is zero then it will not try to read. BTon should equal zero if there is no connection and it should not try to read the port.

I feel like I'm failing at programming101, LOL. FrUsTrAtInG!!
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by davef21370 » Sat May 06, 2017 4:30 pm
Code: Select all
import serial, sys, time

try:
    BTport = serial.Serial("/dev/rfcomm0", baudrate=9600, timeout=3.0)
except serial.SerialException:
    print "Can't open port"
    sys.exit(0)

while True:
    print(BTport.read(1))
    time.sleep(0.001)
Something more like that.

Dave.
Apple say... Monkey do !!
User avatar
Posts: 854
Joined: Fri Sep 21, 2012 4:13 pm
Location: Earth But Not Grounded
by Douglas6 » Sat May 06, 2017 4:37 pm
If the phone is connected, your code will then wait at the read statement for a byte to read. When you close the connection from your phone, the read then fails.

Dave's code is better, but I think you want a try-except around the read, also.
User avatar
Posts: 3872
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL
by AshPowers » Sat May 06, 2017 5:37 pm
Hi Dave!
If I am not connected to the RPi the program aborts immediately because of the print(BTport.read(1)).

If I am connected, the program raises SerialException('device reports readiness to read but returned no data).

The first failure is the deal breaker. This needs to be able to run idle when the phone is not connected, listening for a connection.. Once a connection is made, allow data back/forth, and if the connection is closed, gracefully continue listening for a connection again.
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by AshPowers » Sat May 06, 2017 5:50 pm
Hi Douglas!

It may be of importance to clarify something:

There are TWO SerialException error types I get, depending on what I'm doing.

One of them is when the BTport is attempted to be opened while the phone is not connected.
raise SerialException("could not open port %s: %s".....).. [error 2]

The second one is when the connection is closed:
raise SerialException("device reports readiness to read but returned no data).

Either way, they are both "SerialException" messages so it should know how to handle it. Even if I do not specify a particular error and just use "except:" by itself, which would pass on ANY error, it just seems to get lost.
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by Douglas6 » Sat May 06, 2017 5:57 pm
More important is where the exception occurs. If you are having trouble reading the error, copy and paste the entire error stack here.
User avatar
Posts: 3872
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL
by AshPowers » Sat May 06, 2017 6:13 pm
Douglas,

You hit the nail on the head. I owe you a beer my friend! Yes, I Am an idiot, LOL.

The if loop was sitting at the read(1) statement, waiting for input, and if the connection was closed, that was causing the error.

The solution was to use BTport.inWaiting() to check if there is data and if so, read it and move on.

Like you said, I just didn't know where the exception was occurring and was assuming it was on the opening of the port.

I will do a good bit of cleanup with this ropey code (is that what this word means?) . But at least we got it figured out!

Thanks for the support guys, it is so much appreciated! :)


Code: Select all
import serial
from serial import SerialException
BTon = 0

while 1:
    try:
        BTport = serial.Serial("/dev/rfcomm0", baudrate=9600, timeout=3.0)
        BTport.close()
    except serial.SerialException:
        BTon = 0
    else:
        BTon = 1

    if BTon == 1:
        BTport = serial.Serial("/dev/rfcomm0", baudrate=9600, timeout=3.0)
        datayes = BTport.inWaiting()
        BTport.close()
        if datayes > 0:
            BTport = serial.Serial("/dev/rfcomm0", baudrate=9600, timeout=3.0)
            print(BTport.read(datayes))
            BTport.close()
       
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by AshPowers » Sat May 06, 2017 6:27 pm
BTW, I'm not sure if it is just my machine or if it is Python/Geany, but in times when my current project program has an exception, like a code: 1, I do not always get a message indicating where the program faulted. But for one little short instance of a moment I can see that there was something there. What's up with that?
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by Douglas6 » Sat May 06, 2017 6:34 pm
I'm afraid I'm not familiar with Geany. I write in Nano and run from the command line.
User avatar
Posts: 3872
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL
by paddyg » Sat May 06, 2017 7:08 pm
I think the default Geany setup uses the terminal to run the command (which is probably why some things work ok with Geany but fail with IDLE). Not seeing the error message is possibly because it happens inside the try block, you can display it with
Code: Select all
try:
  ...
except Exception as e:
  print('bad: ', e)

PS opening and closing and opening a serial port every loop doesn't seem a good idea to me. Better to do as Dave suggested; open it once, put the read inside a try (and possibly attempt to reopen serial if there's an exception, again inside a try block).
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 1864
Joined: Sat Jan 28, 2012 11:57 am
by Douglas6 » Sat May 06, 2017 9:28 pm
Something like this, perhaps (lightly tested):
Code: Select all
import time
import serial

conn = None

def openConn():
    global conn

    while True:
        try:
            conn = serial.Serial("/dev/rfcomm0", baudrate=9600)
            return
        except serial.SerialException:
            pass
        time.sleep(1)

openConn()
while True:
    try:
        msg = conn.readline().strip("\n")
        print(msg)
    except serial.SerialException:
        conn.close()
        time.sleep(0.2)
        openConn()
User avatar
Posts: 3872
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL
by AshPowers » Sun May 07, 2017 6:44 am
Paddy,

I think it was one of your posts, somewhere, that you used the word "ropey code"... I've never heard the term "ropey" - ever before that, LOL. Having only been in the community for so short a time I am not familiar with the jargon, but if I were to say what I think it means, this code is a pretty good demonstration of that term. Yea? :)

I will play around with the structure of this section of code to try and optimize it; starting with Douglas' code... I took a more explicit approach in that draft to open-close the port as I was unsure as to whether "trying" to open the port would result in the port actually opening if the attempt to open was successful OR if the "try" to open the port was successful, it didn't actually "open" the port. The explicit approach I took made whatever logic was at play, irrelevant.

Given that I am still putting together the program towards the objectives I've set, code optimization isn't the highest priority at the moment. I will have opportunity after this draft is finished to go back through and refine it. I could even argue that this "ropey" approach is beneficial to learning the nuances of this programming language. Or maybe I'm ropey, LOL. Making all of this work, for me, is like putting together a jigsaw puzzle as a blind man... But, even a blind man can eventually put the picture together.... :)
Last edited by AshPowers on Sun May 07, 2017 7:14 am, edited 2 times in total.
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by AshPowers » Sun May 07, 2017 7:09 am
Douglas,

Thank you for the code example! I will come back around to it once I've got this first draft up and running. :)

I still have a ways to go yet.
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by paddyg » Sun May 07, 2017 7:28 am
You've spotted my secret agenda - seeding this forum with English public (aka private) school slang https://english.stackexchange.com/quest ... or-quality

The main reason for tidy coding is that it's *much* easier to find problems - for other people, but mainly for you! Note Douglas' use of a function (with explicit 'global') rather than repeating code and using clear True and False rather than numbers that happen to work as booleans.
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 1864
Joined: Sat Jan 28, 2012 11:57 am
by Douglas6 » Sun May 07, 2017 12:31 pm
I appreciate the DIY attitude. The worst thing is to nick some bugger's code off the internet (how am I doing, paddyg?) without understanding why it does what it does. But a clean example is a good thing to have to periodically hold your own code against to compare the differences.
User avatar
Posts: 3872
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL
by AshPowers » Mon May 08, 2017 11:31 pm
LOL, Douglas. :)

I do have a question for you about the code you most recently posted up as I came across an issue with the ropey code I've still been running with. Unfortunately opening/closing the port as I was IS causing a problem. I think the timing of those events gets hung up and I can send data from the phone to the RPi for anywhere from 10-20 seconds before it just stops reading any more data. Once I disconnect and reconnect, it is back up and working, but for only around that timespan again.

So I have tested your code in a new blank file and it works just as intended. Only issue is that I am using pi3d and the while DISPLAY.loop_running(): is running, that is where the entirety of the program runs in.

I have been trying to figure out how to use your code within that same loop. Since your code is its own loop based on the boolean condition True/False, I'm not sure how to put that into the display loop without it wanting to get hung up.

Code: Select all
import time
import serial

conn = None

def openConn():
    global conn

    while True:
        try:
            conn = serial.Serial("/dev/rfcomm0", baudrate=9600)
            return
        except serial.SerialException:
            pass
        time.sleep(1)

openConn()

while DISPLAY.loop_running():
<<<pi3d drawing commands here >>>



.
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by Douglas6 » Tue May 09, 2017 12:14 am
I'm afraid I'm not familiar with Pi3d and it's display loop(?). You might need a separate thread, and/or a hook into the UI loop, if that's what it is.
User avatar
Posts: 3872
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL
by AshPowers » Tue May 09, 2017 12:43 am
If you look at the bottom of the code snippet I write, you will see the

while DISPLAY.loop_running():.

This is for pi3d and once the program gets to this loop, it runs in this loop forever, continually redrawing the screen. This is also where all of my data acquisition is occuring through the AD chip as well as OBD automotive engine computer information being pulled through the USB port, etc etc..

I just need help in figuring out how to integrate your serial port code into this.
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by paddyg » Tue May 09, 2017 7:25 am
You could use one loop, putting your pi3d stuff in your serial reading loop or vice-versa but you would then need to make sure you didnt have any blocking reads or long sleeps. you would call loop_running() in the loop (ie it doesn't have to be embedded in while condition, but not bad to have condition for breaking out of loop)

or, better, start a thread to run your hardware i/o. I think the Scenery demo has an example for polling a hall effect sensor
PS to stop serial read blocking you need to use in_waiting and only try to read when there's something there.
PPS just checked and examples I could think of use gpio callback so not so relevant. I meant something like:
Code: Select all
...
msg = None
...
def comm_mon():
  global conn, msg #You could do all your hardware checking in this loop so it doesn't impact on display frame rate.
  # you would need to make variables globals explicitly or pass a general purpose object as an argument.
  while True:
    try:
        msg = conn.readline().strip("\n")
    except serial.SerialException:
        conn.close()
        time.sleep(0.2)
        openConn()
...
t = threading.Thread(target=comm_mon)
t.start()
while DISPLAY.loop_running():
   #pi3d UI stuff
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 1864
Joined: Sat Jan 28, 2012 11:57 am
by AshPowers » Tue May 09, 2017 9:23 pm
Hi Paddy!
I think I follow what you are describing here. I have no experience with the threading function but I have read enough on it to understand that it is basically allowing multiple tasks/functions to run at the same time. In this case, the comm_mon is running at the same time the main while 1 loop is running.

My limited time in using Python is really kicking my butt at this part of the project though, LOL.

My biggest question (I think) is how do I make calls to comm_mon() from within the main "while 1" loop (which in my dash program is the DISPLAY loop)? You can see in the while 1: loop I am just printing the "msg" information but regardless of what I send through from the android, it always just says "None" (and yes, I Am just typing random characters and hitting the return button to send that \n for the readline command).

It looks like it is just saying "None" as that variable is declared as such at the top of the code. Do I have to reference the "msg" value within the comm_mon function? If so, how is that performed? How would I invoke a "Send" command to transfer information to the android from within the while 1 loop?

I know these are total noob questions but I've only been at this for a few weeks now..
BTW, without the print command in the while loop, this code will not run. I get a name error: global name "conn" is not defined. Not sure why it doesn't do this if the print(msg) is in the while 1 loop.

Code: Select all
msg = None

def openConn():
   global conn
   
   while True:
      try:
         conn = serial.Serial("/dev/rfcomm0", baudrate=9600)
         return
      except serial.SerialException:
         pass

def comm_mon():
   global conn, msg
   while True:
      try:
         msg = conn.readline().strip("\n")
      except serial.SerialException:
         conn.close()
         time.sleep(0.2)
         openConn()
         
t = threading.Thread(target=comm_mon)
t.start()

while 1:
   print(msg)
Posts: 75
Joined: Thu Apr 20, 2017 12:10 am
Location: Ormond Beach, FL
by paddyg » Tue May 09, 2017 10:03 pm
not really sure, it locks sensible, but these might be issues: without a sleep() for a small time your wine loop will run VERY fast possibly you will print thousands of Nones between each msg. put a if msg is not None: condition on your print and time. sleep(0.1) If you don't have anything in your while loop it might not work, as expected (empty blocks usually need a pass) but the comm error ptobably comes from comm.close() happening before creating the serial connection ie you need to run openCom() once before you start your thread.

to send messages simply use another global and in comm_mon if it's not None send it over setial (then set to None)
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d
User avatar
Posts: 1864
Joined: Sat Jan 28, 2012 11:57 am