树莓派学习笔记2: 用python实现C/S方式远程控制双色LED灯

@2018年12月29日

  • 一、背景
    在之前两篇博客中,学习记录了python控制LED灯、套接字C/S通信。如
    1.树莓派学习笔记1:python控制双色LED灯(https://blog.csdn.net/weixin_44230447/article/details/85223640)
    2.Python学习笔记1:套接字编程-服务和客户端(https://blog.csdn.net/weixin_44230447/article/details/85267244)
    基本原理和简单程序实现后,元旦期间对程序又进行了修改,主要是服务端程序修改较多。

  • 二、基本原理和实验环境
    1.硬件:树莓派及LED,参考树莓派学习笔记1
    2.软件:

  • 服务端程序,部署在树莓派上,host 如192.168.1.107;

  • 客户端程序,本地pc上,可以是一python程序,也可是telnet工具。

  • 树莓派和客户端终端,都接入一个局域网。跨域的还没试过。

在客户端通过 socket与远端建立TCP连接,发送指令字符到树莓派上服务端程序,按指令调用GPIO语句,控制电平高低,最终控制红绿LED的开关。

  • 三、python+树莓派实现
    (一)服务端程序
# -*- coding:utf-8 -*-
# Socket Server example in python 3.6
# 文件名:Socket_server_test.py
import socket
import sys

import RPi.GPIO as GPIO
import time
# ------------------------------------------------------------------
HOST = ''  # Symbolic name meaning all available interfaces
PORT = 8888  # Arbitrary non-privileged port
timeout_limit=120     # unit-sec,建立连接后如果超过xx 秒,将断开连接
connect_times_limit=5 # unit-times,连接中断次数达到xx 次,将关闭socket和中止服务端程序。
#------------------------------------------------------------------
pins = {'pin_R':11, 'pin_G':12}  # pins is a dict
sleep_time = 5
GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
for i in pins:
	GPIO.setup(pins[i], GPIO.OUT)   # Set pins' mode is output
	GPIO.output(pins[i], GPIO.LOW) # Set pins to low(0V) to off led
	print("i is ",i,pins[i])

def Let_Led_on(pin):
        print('The pin is',pin)
        if pin=='pin_R' :
            other_pin='pin_G'
        elif pin=='pin_G' :
            other_pin='pin_R'
        else :
            print('Input error.\r\n')
            
        GPIO.output(pins[other_pin], GPIO.LOW) # Set pins to low(0V) to off led
            
        GPIO.output(pins[pin], GPIO.HIGH)   # Set pins to high(+3.3V) to on led
        print(pins[pin]," Red Led is On...")
        time.sleep(sleep_time)
# ---Let_led_on----------------------------------           

def Let_Led_off():
                   
        GPIO.output(pins['pin_R'], GPIO.LOW) # Set pins to low(0V) to off led
        time.sleep(1)
        GPIO.output(pins['pin_G'], GPIO.LOW) # Set pins to low(0V) to off led    
        
        print(" Red and Green LEDs is off.")
        
# ---Let_led_off----------------------------------           
#------------------------------------------------------------------
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('1.Socket created')

try:
    s.bind((HOST, PORT))
except socket.error as msg:
    print('>> Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
    sys.exit()

print('2.Socket bind complete')

s.listen(10)
print('3.Socket now listening')

quit_count=0  # initial

while 1:
    # wait to accept a connection - blocking call
    conn, addr = s.accept()
    quit_count = quit_count + 1
    print('4.Connected with ' + addr[0] + ':' + str(addr[1]),',now is ',quit_count,' times connect')

    welcome_str='Hello, Welcome to here..The input value must be :\r\n' \
                +'  r : red led on\r\n'\
                +'  g : green led on\r\n'\
                +'  o : Two leds off\r\n'\
                +'  q : quit the connection\r\n'
    conn.sendall(welcome_str.encode())

    try:
        conn.settimeout(timeout_limit)
        # 获得一个连接,然后开始循环处理这个连接发送的信息

        while True:
            try:
                data = conn.recv(1024)
            except IOError as rcv_msg:
                print(">> Failed to recv() data.: %s: %s\n" % (rcv_msg.errno, rcv_msg.strerror))
                break

            buf = data.decode()

            print( "<< Get value " + buf)
            if buf == 'r':
                print("<< Red LED is on")
                conn.sendall('>> Red LED is on...\r\n'.encode())
                '''
                do something...
                '''
                Let_Led_on('pin_R')
            elif buf == 'g':
                print("<< Green LED is on")
                conn.sendall('>> Green LED is on...\r\n'.encode())
                '''
                do something...
                '''
                Let_Led_on('pin_G')
            elif buf =='o':
                print("<< Two LEDs turn off.")
                conn.sendall('>> Green and Red LED turn off!\r\n'.encode())
                '''
                do something...
                '''
                Let_Led_off()
            elif buf =='q':
                Let_Led_off()    
                print("<< The Connection Close")
                conn.sendall('>> The Connection will Close in 3 sec, Rerun again.\r\n'.encode())
                break
            else:
                print("<< Invalid command, try again!")
                conn.sendall('>> Invalid command, pls try again!\r\n'.encode())
    except socket.timeout:  # 如果建立连接后,该连接在设定的时间内无数据发来,则time out
        print('time out')

    conn.close()
    print("5.This Connection ",addr[0]," has disconnected.")
    if  quit_count ==connect_times_limit :  # 如果q(quit),即断开连接次数达到一定次数后,将关闭socket.
        break
print("6.Socket close,When quit times = ",quit_count)
s.close()

(二)客户端程序
可参考之前文章,收发数据要加一个循环,如下:

#!/usr/bin/python3
# 文件名:Socket_client_simp_test.py
# 参考:https://blog.csdn.net/qq_25406669/article/details/80576770

# 导入 socket、sys 模块
import socket
import sys
import time

# 创建 socket 对象
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('1.Socket created')

# 获取本地主机名
#host = socket.gethostname()
#host='localhost'
host='192.168.1.107'
# 设置端口号
port = 8888

# 连接服务,指定主机和端口
try:
    print(">> This connection will connect to host:", host)
    s.connect((host, port))
except IOError as e:
    print(">> Failed to connect host.: %s: %s\n" % (e.errno, e.strerror))
    sys.exit()
print("2.Connected with host ",host,":",port)

# 接收小于 1024 字节的数据
msg1 = s.recv(1024)
print('Server Say: ',msg1.decode('utf-8'))

while True:
    in_cmd = input('please input :')
    try:
        s.sendall(in_cmd.encode())
        srv_reply=s.recv(1024).decode()
    except IOError as rcv_msg:
        print("Failed to sendall() or recv() data.: %s: %s\n" % (rcv_msg.errno, rcv_msg.strerror))
        break
    print('Server reply : ',srv_reply)
    if in_cmd=='q':
        #print(in_cmd)
        time.sleep(3)  # wait 3 sec ,and break
        break

print('The connection disconnected!')
s.close()
  • 还可更简单,通过telnet 直接登录服务端。目前windows telnet 至少可发一个字符,但手机上通过juiceSHH (Andriod app)telnet可连入服务端,但无论输入什么,都当做无效字符,推测字符集问题。windows telnet 结果如下:
    树莓派学习笔记2: 用python实现C/S方式远程控制双色LED灯_第1张图片

    至此,基于上述程序, 可实现简单的client/server 方式,在本地局域网内控制树莓派。下一步,再考虑在手机上 实现web远程控制,目前初步了解有flask和webiopi,以及微信小程序。

你可能感兴趣的:(Raspberry,Python)