using Split in Python

2

In my program, my Raspberry receives a call for a GSM module and for the serial receipt

RING



+CLIP: "633555999",161,"",0,"",0

every time it gives a tone (I've invented the number). What I need is that of all this string that sends me, separate the word RING to detect when they call me and then separate the phone number to send an SMS later. I leave my program:

import serial
import time
from curses import ascii
sSerie = serial.Serial('/dev/ttyS0',9600)
while True:
    try:
        llamando1 = sSerie.readline()
        a,b= llamando1.split("+")
        print a
        if a == "RING":
            num = sSerie.readline()
            morralla, numero, morralla2 = num.split('"',2)
            sSerie.write('ATH\r\n')
            print 'numero que te ha llamado =' + str(numero)


    except KeyboardInterrupt:
                quit()

With this program I can not compare the variable a with the RING and I get this:

File "testllamada.py", line 8, in <module>
    a,b = llamando1.split(" ")
ValueError: need more than 1 value to unpack

If I only put a instead of a,b if it separates me but with the print a I get something similar to this:

[\n\r]
[RING\n\r]
[\n\r]
[( ,) CLIP: "633555999",161,"",0,"",0\n\r]

And I do not know how to take only the second line. If someone can help me, I will be very grateful.

    
asked by wasous 19.07.2017 в 17:27
source

2 answers

2

From what I understood, you read lines from a port and process them sequentially, if a line RING appears you should wait at some point for a line CLIP: . To simulate this behavior, prepare a list of lines to receive and iterate over them in the order of arrival

lineas = ["", "RING", "", "", "","+CLIP: ""633555999"",161,"""",0,"""",0"]

estado = -1
for l in lineas:

  if l == "RING":
    estado == 1 # Llamada

  if estado == 1:
    if l[:5] == "+CLIP":
      numero = l[7:].split(",")[0]
      print 'numero que te ha llamado =' + numero
      estado = -1

What is done is:

  • Upon receiving a RING we establish a estado = 1 state that represents that we are currently processing a call, this to differentiate logics from other possible operations. The concrete thing is that the system will wait for a +CLIP to finish the logic
  • If the following line has the text +CLIP: (we use a "string slice" using l[:5] ) we simply cut the line by the text after +CLIP: and make a split() with the comma as a separator, that would return something like this: ['633555999', '161', '', '0', '', '0'] , so using the index we easily obtain the data we are looking for
  • Finally, we return the state to -1 to restart the cycle, and the system would wait for the next "operation".
  • This is a very basic way of solving the problem, adapting it to your code, it would be something like this:

    import serial
    import time
    from curses import ascii
    
    sSerie = serial.Serial('/dev/ttyS0',9600)
    estado = -1
    while True:
        try:
            l = sSerie.readline()
    
            if a == "RING":
               estado = 1 # Llamada
    
            if estado == 1:
               if l[:5] == "+CLIP":
                 numero = l[7:].split(",")[0]
                 sSerie.write('ATH\r\n')
                 print 'numero que te ha llamado =' + numero
                 estado = -1
    
        except KeyboardInterrupt:
                    quit()
    

    If, as you mention in your last comment, you do not receive line by line but the complete text, it is much easier to do the following:

    txt ="""RING
    
    
    
    +CLIP: "633555999",161,"",0,"",0"""
    
    lista = txt.split()
    
    if len(lista) >= 3 and lista[0] == "RING":
      numero = lista[2].split(",")[0].replace('"','')
      print("Numero: {}".format(numero))
    

    First of all, we are left with each of the texts using spaces or end of line characters as a separator ( lista = txt.split() ), this returns a list like the following:

    ['RING', '+CLIP:', '"633555999",161,"",0,"",0']
    

    Thus we already have more clear how to recover the number, but as we do not know if we will always receive this single text it is advisable to be cautious and verify that at least we obtained three chains, and that the first one is that the first one is "RING", this is how the number will be the third string on the list, and on this we re-apply the split() this time separating , , the first value is the number.

    I hope it's useful for you.

        
    answered by 19.07.2017 / 18:40
    source
    0
    >>> serial.Serial.read_all.__doc__
    '        Read all bytes currently available in the buffer of the OS.\n        '
    

    Instead of using readline you could read everything at once, check if "RING" is in the string that returns it and then search for the number using split or regular expressions. The thing about regular expressions has the advantage that if you have received more than one call since the last reading, you can easily obtain all the hit numbers. Although I think it's not very plausible to happen.

    >>> data
    'RING\n\n\n\n+CLIP: "633555999",161,"",0,"",0RING\n\n\n\n+CLIP: "633555888",161,"",0,"",0RING\n\n\n\n+CLIP: "633555777",161,"",0,"",0'
    >>> pattern = re.compile("""RING.*?CLIP: "(\d*)""", re.DOTALL)
    >>> re.findall(pattern, data)
    ['633555999', '633555888', '633555777']
    

    NOTE: It is possible that if you do not use the flushOutput method every time you call the read_all method, you will always return the previous text + the new one, I am not sure, do tests because I do not know if when calling read_all the buffer is cleaned or no.

        
    answered by 20.07.2017 в 01:56