Forum: Mikrocontroller und Digitale Elektronik Raspberry Pi - Socket-Konfiguration


von Thorsten (Gast)


Lesenswert?

Hallo,

ich beschäftige mich grade mit meinem Raspberry Pi, indem ich mit der 
App fürs Smartphone NetIO versuche eine LED an meinen Raspberry 
anzusteuern.
das klappt auch soweit alles seht gut.

Jetzt möchte ich gernen im nächsten schritt die per App gesendeten Daten 
über UART versenden.

Doch bevor ich dieses in Angriff nehme, sitz ich jetzt schon ewig dabei, 
zu versuchen, wie man es in Python hinbekommt, dass die IP Verbindung 
zur App nicht jedesmal wieder neu aufgesetzt werden muss, indem man das 
Programm neu startet.

Irgendwie muss die Verbindung bei jedem Verbindungsabbruch zurückgesetzt 
werden.

Hat da jemand von euch schon mal was gemacht ?

Hier hab ich mal den Code von http://netio.davideickhoff.de/ 
reingepackt:
1
#!/usr/bin/python 
2
3
# Echo server program
4
import socket
5
import RPi.GPIO as GPIO
6
7
#####################################################################
8
#### SETUP IOs ######################################################
9
#####################################################################
10
# to use Raspberry Pi board pin numbers
11
GPIO.setmode(GPIO.BCM)
12
# For LED1 we use pin 4 according BCM pin count 
13
# (see https://projects.drogon.net/raspberry-pi/wiringpi/pins/)
14
LED1 = 4
15
# For Switch input we use pin 17 according BCM pin count
16
SWITCH1 = 17
17
# set up GPIO output channel
18
GPIO.setup(LED1, GPIO.OUT)
19
20
# set up GPIO input with pull-up control
21
#   (pull_up_down be PUD_OFF, PUD_UP or PUD_DOWN, default PUD_OFF)
22
GPIO.setup(SWITCH1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
23
24
25
#####################################################################
26
#### SETUP SOCKET INTERFASE #########################################
27
#####################################################################
28
HOST = ''                 # Symbolic name meaning the local host
29
PORT = 54321              # Arbitrary non-privileged port
30
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
31
s.bind((HOST, PORT))
32
s.listen(1)
33
conn, addr = s.accept()
34
print 'Connected by', addr
35
#####################################################################
36
#### Continous loop, that waits for new data and acts depending  ####
37
#### on data content on it                                       ####
38
#####################################################################
39
while 1:
40
    data = conn.recv(1024)
41
    print 'New Receive', data
42
    if not data: break
43
    print 'Received Data:', data
44
    if data == 'LED1 on\n':
45
        conn.send('on')
46
        GPIO.output(LED1, GPIO.HIGH)
47
        print 'received on'
48
    elif data == 'LED1 off\n':
49
        conn.send('off')
50
        GPIO.output(LED1, GPIO.LOW)
51
        print 'received off'
52
    elif data == 'get status\n':
53
        print 'Input Status:', GPIO.input(SWITCH1)
54
        if GPIO.input(SWITCH1):
55
           conn.send('on')  
56
           print 'Read GIOP 0 result On'
57
        else:
58
           conn.send('off')  
59
           print 'Read GIOP 0 result Off'
60
        # ende if
61
    else:
62
        conn.send('unknown command')
63
        print 'Unknown command:', data
64
    # continue with while 1
65
conn.close()

Schönen Abend noch

von Conny G. (conny_g)


Lesenswert?

Hallo Thorsten,

das Problem ist hier, dass Dein Progrämmchen so geschrieben ist, dass es 
nur eine Verbindung annimmt:

Zu Beginn
1
s.bind((HOST, PORT))
2
s.listen(1)
3
conn, addr = s.accept()

d.h. Du hängst Dich an den TCP/IP Port (bind), wartest auf eine 
Verbindung (listen) und nimmst Sie an (accept).
Dann gehst Du in die Endlosschleife (while (1)) um die Daten zu 
verarbeiten.
Wenn nichts mehr kommt hast Du ein Problem:
das Programm hängt in der Endlosschleife, aber es existiert keine 
Verbindung mehr.

D.h. Du müsstest das Annehmen der Verbindung in die Schleife 
hineinnehmen und richtig auf Verbindungsabbruch/-Ende mit der Gegenseite 
reagieren (vermutlich close, evtl. nochmal listen).

D.h. Deine Schleife sähe schnell hingeschrieben in etwa so aus:
1
bind
2
listen
3
modus = warten auf verbindung
4
while (1)
5
  prüfen auf eingehende verbindung
6
  wenn eingehende verbindung
7
       accept
8
       modus = daten empfangen
9
  wenn modus == daten empfangen
10
      daten vorhanden?
11
          ja: daten empfangen, daten verarbeiten
12
          nein: nach x Zeit keine Daten: aktiv Verbindung trennen,
13
                 ggf verbindungsannahme neu initialisieren
14
                 modus = warten auf Verbindung
15
      verbindungsabbruch von gegenseite:
16
          close
17
          evtl. verbindungsannahme neu initialisieren
18
          modus = warten auf Verbindung

Evtl. muss man noch abfangen, dass man nicht mehr als 1 Verbindung 
annimmt - sonst wird's etwas komplizierter, wenn man mehrere 
Verbindungen verwalten will.

Vg,
Conny

von Conny G. (conny_g)


Lesenswert?

Dafür müssten sich übrigens Code-Beispiele finden lassen, wie man die 
Connections beendet und wieder annimmt - jeder selbstgebaute Python 
Simple/Mini-Webserver macht das.

von Bastler (Gast)


Lesenswert?


von Bastler (Gast)


Lesenswert?


von Conny G. (conny_g)


Lesenswert?

Perfekt!

von Thorsten (Gast)


Angehängte Dateien:

Lesenswert?

Vielen dank für die vielen und vor allem super Antworten.

Das mit den mehreren Verbindungen klappt super und ich kann mich mit 
mehreren Clienten anmelden.

Jetzt kommt mein nächstes Problem. ich habe einen Beispielcode für UART 
aus dem Netz gezogen, um einmal die Verbindung über UART zu testen.

Dazu habe ich einen Pegelwandler zwischen Raspberry und Pc geklemmt. Die 
Verbindung funktioniert auch prima und ich kann daten zum Pc schicken. 
Soabl ich aber versuche daten vom Pc zu empfangen, schmiert das Programm 
auf dem Pi immer ab.

In den Anhang habe ich mal einen Sreenshot gepackt, auf dem man in SSH 
die konsole und dann HTerm auf dem Pc sehen kann, welche Fehlermeldung 
kommt.

Woran liegt das, also das Programm wurde im Netz als funktionsfähig 
beschrieben.
1
 # Serial Interface Raspberry Pi <----> ATXMEGA
2
3
import serial
4
import time
5
import platform
6
import decimal
7
import binascii
8
9
10
11
12
print "......Start Program....."
13
print "OS Name = ", platform.system()
14
print "Time/Date = ", time.asctime()
15
16
17
# Some String conversions as Python lessons
18
# Convert decimal to string
19
dec = decimal.Decimal("12")
20
dec = dec * 3
21
print str(dec)
22
23
24
# convert hex to ASCII string --> &H41 --> "A" ....
25
my_string = "41424344454647"
26
print binascii.unhexlify(my_string)
27
28
29
# or
30
31
32
print my_string.decode("hex")
33
34
35
# Using a bytearray
36
bytes = bytearray(b"ABDCEFGHIJKLMNOPQRSTV")
37
# 65 decimal = "A" ASCII
38
print bytes[0]
39
print bytes[1]
40
 
41
42
43
# configure the serial port of raspberry pi (ttyAMA0)
44
# Make sure this port will not be used by the system like Syslog....
45
ser = serial.Serial(
46
    port="/dev/ttyAMA0",
47
    baudrate=9600,
48
    parity=serial.PARITY_NONE,
49
    stopbits=serial.STOPBITS_ONE,
50
    bytesize=serial.EIGHTBITS,
51
    #timeout=10, # timout in seconds
52
    xonxoff=0, # Software flow control
53
    rtscts=0,  # hardware (RTS/CTS) flow control
54
    dsrdtr=0,  # hardware (DSR/DTR) flow control
55
    interCharTimeout=None 
56
)
57
58
59
# Check if port is open
60
if ser.isOpen() == True:
61
    print "ttyAMA0 is open !"
62
else:
63
    print "Error open ttyAMA0"
64
65
66
67
68
ser.write("\x0D"+"\x0A")
69
output = "Hello ATXMEGA_1"+chr(13)+chr(10)  # Carriage Return solution 1
70
ser.write(output)
71
output = "Hello ATXMEGA_2"+"\x0D"+"\x0A"  # Carriage Return solution 2
72
ser.write(output)
73
74
75
ser.flushInput()    # Flush input buffer
76
77
78
while 1:
79
    time.sleep(2)   # sleep 2 seconds
80
    # Request the data from ATXMEGA by sending ">"
81
    ser.write(">")
82
    # Wait for data from ATXMEGA
83
    response =ser.readline()
84
    
85
    print "Len = ", len(response)
86
    print response
87
    
88
89
90
    # If we receive exit then exit the while loop
91
    if response == "exit"+chr(13)+chr(10):
92
        print "End program"
93
        break    
94
# ASCII data in Python e.g. chr(13)
95
96
97
# Read a "/n" terminated line# 
98
#response =ser.readlineeadline()
99
100
101
# print the received string
102
print "Now close ttyAMA0"
103
ser.close()

von Conny G. (conny_g)


Lesenswert?

Hallo Thorsten,

also die Fehlermeldung und Fehlererscheinung sagt mir gerade nichts.
Der Code sieht bei einem schnellen Überflug auch ok aus.

Eins was mir mal Ärger gemacht hat:
beim Raspberry Pi hängt standardmässig die Console am seriellen Port, 
hast Du den auch abgehängt?

Das geht so:
- in /etc/inittab die Zeile "T0:23:respawn:/sbin/getty -L ttyAMA0 115200 
vt100" auskommentieren
- in /boot/cmdline.txt den Teil "console=ttyAMA0,115200" entfernen

Vg,
Conny

von Thorsten (Gast)


Lesenswert?

Hallo Conny,

genau daran hat es gelegen......... Man und das hat mich etliche Stunden 
gekostet. Wo kann man sowas denn nachlesen, weil ich hab sowas nirgendwo 
gefunden.

Kann mir noch jemand sagen, ob  es für die UART Schnittstelle auch sowas 
wie eine UART Variable gibt, nach welcher man abfragen kann, ob 
überhaupt igendetwas gesendet worden ist, damit man nicht immer auf eine 
Nachricht warten muss. Sowas wie:

if (UART hat Daten empfangen = 1)
   Daten auswerten
   print (Daten)
else
   normaler Programmablauf

Ich versuch mich da immer an der C-Programmierung zu orientieren, da 
gibt es sowas ja.....

MfG

von David (Gast)


Lesenswert?

Hallo zusammen, gibt verschiedene Möglichkeiten bzgl. des TCP Servers.
Ein gut funktionierendes Beispiel gibt es hier:

http://netio.davideickhoff.de/forum/topic/66/

Direkt Download: 
http://netio.davideickhoff.de/forum/attachment/8f9094943777bf231b6fba9b0c71731fff9ccd92/

In der handle_command Funktion kommen dann deine Anpassungen rein.

von Conny G. (conny_g)


Lesenswert?

Hi Thorsten,

serielle Console abschalten: das hab ich auch mal irgendwo gelesen, als 
ich schon einiges an seltsamen Effekten damit hatte :-)
Hier hab ich's grad wiedergefunden:
http://www.hobbytronics.co.uk/raspberry-pi-serial-port

Du meinst einen "non-blocking call" für's Zeichen lesen von Uart in 
Python?

Das gibt's. Du kannst entweder das zeilenweise Lesen in einen eigenen 
Thread verlagern:
http://stackoverflow.com/questions/17553543/pyserial-non-blocking-read-loop

oder Du liest einzelne Zeichen und wertest aus, ob Du überhaupt etwas 
bekommen hast:

1
ser = serial.Serial( '/dev/ttyAMA0', 38400, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=0, xonxoff$
2
3
def handle_data(data):
4
    sys.stdout.write( '%s' % data )
5
6
def read_from_port():
7
        while running:
8
           data  = ser.read()
9
           if data:
10
             handle_data(data)
11
12
thread = threading.Thread(target=read_from_port)
13
thread.start()

Das "timeout=0" und "if data:" ist der Trick.

http://raspberrypi.stackexchange.com/questions/9419/how-to-read-values-with-pyserial

Vg,
Conny

: Bearbeitet durch User
von lasse (Gast)


Lesenswert?

Hallo, wie programmiere ich das ich die GPIO Pins beim Raspberry PI so 
dass ich sie über Bluetooth ansteuern kann also dann zb. über eine App. 
Hat jemand ne IDEE??

von Conny G. (conny_g)


Lesenswert?

lasse schrieb:
> Hallo, wie programmiere ich das ich die GPIO Pins beim Raspberry PI so
> dass ich sie über Bluetooth ansteuern kann also dann zb. über eine App.
> Hat jemand ne IDEE??

Entweder Du programmierst Dir einen entsprechenden Service auf dem RPi 
und eine App oder Du recherchierst, ob das schon jemand gemacht hat.
Die Wahrscheinlichkeit ist äußerst hoch, dass das schon jemand gemacht 
hat.

Voila, erster Treffer in Google:

https://behindthesciences.com/electronics/controlling-raspberry-pi-gpios-over-bluetooth-with-an-android-app/

https://www.google.de/search?&q=switch+gpio+raspberry+pi+via+bluetooth

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.