标签 Python 下的文章

之前一直用Arduino,现在来尝试一下Python。

烧录

1. 到官网下载固件

http://www.micropython.org/download

2. 安装esptool工具

请确保有Python环境(Linux或Windows)

pip install esptool

3. 清空Flash

这一步很重要,可以避免很多错误:

esptool.py --port /dev/ttyUSB0 erase_flash (Windows下port为COM口)

4. 下载到ESP8266上

下载前先将GPIO0下拉,进入下载模式:

esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20180511-v1.9.4.bin

有些模块的Flash是512K的,可能无法下载固件,可以通过esptool来查看:

esptool.py --port /dev/ttyUSB0 flash_id

连接WiFi与远程编程

通过串口连接ESP8266,可以看到串口输出:
25_0.PNG
依次输入:

>>> import network
>>> sta_if = network.WLAN(network.STA_IF)
>>> sta_if.active(True)
>>> sta_if.connect("", "") #SSID,PASSWD
>>> sta_if.isconnected()
>>> print("IP:",sta_if.ifconfig()[0])

连接后可以看到模块的IP。
远程编程需要用到webrepl,你可以使用MicroPython的在线客户端,或从Github获取:

  1. Github:https://github.com/micropython/webrepl
  2. 在线客户端:http://micropython.org/webrepl

在使用webrepl前,需要进行配置,在串口输入:

>>> import webrepl_setup #按提示配置

配置完成后再在串口输入下面的代码,来开启:

>>> import webrepl
>>> webrepl.start()

你可以通过webrepl来上传/下载文件。
webrepl的界面:
25_1.PNG

文件系统

输入下面命令查看当前有的文件:

 >>> os.listdir()
 ['boot.py', 'webrepl_cfg.py', 'main.py']
 boot.py main.py前被执行(开发板启动时将执行这个该脚本,它设置了开发板的多个选项参数) | main.py 主程序

查看剩余空间:

>>> import micropython
>>> micropython.mem_info()
stack: 2112 out of 8192
GC: total: 35968, used: 10000, free: 25968
No. of 1-blocks: 44, 2-blocks: 15, max blk sz: 264, max free sz: 1417

文档

http://docs.micropython.org/en/latest/library/index.html#python-standard-libraries-and-micro-libraries

生成公私钥

当然也可以用Rsa模块来生成,不过还是使用openssl吧。
生成一个1024bit的私钥,便于试验,私钥要妥善保管:

openssl genrsa -out private.key 1024

由私钥生成公钥:

openssl rsa -in private.key -pubout -out public.key

你可以使用cat来查看你的私钥或公钥,他应该由如下格式组成:

//私钥
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDhlMzeKVyiyZHVH5a40o......
-----END RSA PRIVATE KEY-----
//公钥
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQ......
-----END PUBLIC KEY-----

Python下

Python2.7环境:

#coding=utf-8
import rsa
import base64
#简单的封装一下
def readfile(filename):
    f = open(filename,'r')
    buf = f.read()
    f.close()
    return buf
def loadkey(private_key,public_key): #加载私钥公钥
    pri = rsa.PrivateKey.load_pkcs1(private_key.encode())
    pub = rsa.PublicKey.load_pkcs1(public_key.encode())
    return pri,pub
def rsa_encrypt(public_key,message): #使用公钥加密,加密后返回的是二进制流,所以用base64模块转成字符串
    return base64.b64encode(rsa.encrypt(message.encode(),public_key))
def rsa_decrypt(private_key,message): #私钥解密,用base64模块转回二进制流解密
    return rsa.decrypt(base64.b64decode(message),private_key).decode()

if __name__ == '__main__':
    private_key,public_key = loadkey(readfile('private.key'),readfile('public.key'))
    message = 'test'
    encrypt_text = rsa_encrypt(public_key,message)
    print encrypt_text
    print rsa_decrypt(private_key,encrypt_text)

返回如下:

HXowzHMPD5vJ4CcAbCoQT1COUnnjqC4w6lu7UH255myj1CZFrCobBDCmDuNRRBxhmOS21SObDt5x5vAaJJcT4WexRNrA0pp3cem+73ea0TD0hH1CoETHo+NxOX0TS2/+sJG0/w8OY1MsXS43RhEt2iUWcUKpbzEI/aBu8T6kzdo=
test

Python下自带的Socket的模块是阻塞型的,每次只能处理一个连接,给应用造成了极大的不便,幸好有Gevent这个基于 协程的网络库,来使默认的Socket支持并发。

代码如下:

#coding=utf-8
from gevent import monkey; monkey.patch_all() //猴子魔法[1]
import socket
import gevent

def server_req(conn):
        while True:
                data = conn.recv(1024) #等待传入数据
                if not data:
                        conn.close() #关闭连接
                        break
                print('recv:%s'%data)
                conn.send(data) #发送数据

def server_mian(s_addr,s_port):
        s = socket.socket()
        s.bind((s_addr,s_port)) #绑定端口
        s.listen(500) #最大连接数
        while True:
                cli,addr = s.accept() #等待一个客户
                gevent.spawn(server_req,cli) #创建一个协程,将客户传入server_req函数

if __name__ == '__main__':
    server_mian('0.0.0.0',3000)

[1]猴子魔法(Monkey Patch):https://www.gevent.org/api/gevent.monkey.html

TkinterPython的标准GUI库。Python使用Tkinter可以快速的创建GUI应用程序。

下面我们来通过一个简单的例子来用用它

#coding=utf-8
#Python3环境
import tkinter

def button():
    print('被点了')

if __name__ == '__main__':
    root = tkinter.Tk()
    root.title('测试窗口')
    root.geometry('300x250') #设置窗口大小(宽x高)
    root.resizable(False,False) #禁止调整窗口大小(宽x高)
    tkinter.Button(root,text='点我,点我',bg='#66ccff',command=button).pack()
    #bg:按钮背景色
    #command:按钮绑定事件
    root.mainloop() #窗口循环事件

638_0.png

某个同学拿去开老师玩笑,用这个搞了一段音频,后来他走的很安详。

#coding=utf-8
#百度语音合成 by blog.chutian.bid
import requests,json,sys
class baidutoaudio:
    def __init__(self,appKey,appSecret,Cuid):
        self.ak = appKey
        self.sk = appSecret
        self.cuid = Cuid
        self.token = self.gettoken(appKey,appSecret)
        return
    def utf8(self): #UTF8环境
        reload(sys)
        sys.setdefaultencoding('utf-8')
    def getapi(self,url):
        data = requests.get(url)
        return data.text
    def writeauido(self,url,file): #写音频
        data = requests.get(url)
        f = open(file, 'w+')
        f.write(data.content)
        f.close()
    def gettoken(self,ak,sk): #获取鉴权
        data = self.getapi('https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + ak + '&client_secret=' + sk)
        if(data.find('error_description') == -1):
            data = json.loads(data)
            return data['access_token']
        else:
            data = json.loads(data)
            print data['error_description']
            return 'ERROR'
    def getsay(self,tex,spd,pit,vol,per,file): #写音频并返回链接
        #tex:合成用文本 spd:语速 pit:音调 vol:音量 per:发音人选择
        #0为普通女声,1为普通男生,3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女声
        url = 'http://tsn.baidu.com/text2audio'
        url += '?tex='
        url += str(tex)
        url += '&tok='
        url += self.token
        url += '&cuid='
        url += str(self.cuid)
        url += '&ctp=1&lan=zh'
        url += '&spd='
        url += str(spd)
        url += '&vol='
        url += str(vol)
        url += '&per='
        url += str(per)
        self.writeauido(url,file)
        return url
if __name__ == '__main__':
    appKey = 'You AK'#AK
    appSecret = 'You SK'#SK
    cuid = '1'#用户ID
    say = baidutoaudio(appKey,appSecret,cuid)
    say.utf8()
    print say.getsay(raw_input('Say:'),5,6,12,4,'say.mp3')

安装模块:

apt install python-opencv python-flask
(自动处理依赖关系)

源码:

1.easycamera

#coding=utf-8
#摄像头模块
import cv2
class easycamera:
    def __init__(self,cameraid): #初始化
        self.cap = cv2.VideoCapture(cameraid)
    def setimage(self,height,width): #设置图像高度宽度
        self.cap.set(3,width)
        self.cap.set(4,height)
    def getimage(self,format = '.jpg'): #读取图像
        ret,image = self.cap.read()
        ret,image = cv2.imencode(format,image)
        return image.tobytes()
    def writeimage(self,filename): #写图像
        ret,image = self.cap.read()
        ret,image = cv2.imencode(format,image)
        f = open(file,'w')
        f.write(image.tobytes())
        f.close()
    def getcamerainfo(self): #获取图像高度宽度
        return {'width':self.cap.get(3),'height':self.cap.get(4)}

2.server

#coding=utf-8
#服务器模块
from flask import Flask,Response
from camera import easycamera

app = Flask(__name__)
def getimage(id): #产生流
    image = easycamera(id)
    image.setimage(720,1280)
    while True:
        data = image.getimage()
        yield('--frame\r\n Content-Type: image/jpeg\r\n\r\n' + data + b'\r\n\r\n')

@app.route('/')
def index(): #主页,简单的html拼凑
    return '<html><body><h1>Web Camera</h1><img src="/getcamera"></body></html>'

@app.route('/getcamera') #取图像
def getcamera():
    return Response(getimage(0),mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(host='0.0.0.0',port=80, debug=True)

解析:

mimetype='multipart/x-mixed-replace; boundary=frame'

游览器报文,请参考这篇文章,在这里是服务器向游览器发送图片流。

yield

类似于return,但与return不同的是,return执行后就不再执行return后的代码了,而yield返回后会继续执行后面的代码,在上面的代码中,不断的返回图片数据(流),请参考这篇文章。

效果:

有一定的延迟,帧数还是算流畅的。

412_0.png

需要安装Python-Opencv:

apt install python-opencv
(自动处理依赖关系)

一段简短的代码:

#coding=utf-8
import cv2,time
cap = cv2.VideoCapture(0) #选择设备
cap.set(3,1280) #设置宽度(720p)
cap.set(4,720) #设置高度
while(1):
    file = 'photo/' + time.strftime('%Y-%m-%d-%H:%M:%S',time.localtime(time.time())) + '.jpg' #存储在photo文件夹,以时间命名,JPG格式
    print 'GET',file
    ret,photo = cap.read()  #读取摄像头
    cv2.imwrite(file,photo) #写照片
    time.sleep(10) #延时时间,10s一张

之后照片用FFmpeg之类的工具合成视频就可以了。

写这个是为了下载纪录片用的。

比如这个页面:舌尖上的中国第二季

它会抓取这个页面的所有视频链接并输出到txt文件。

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import requests,re,os
#取网页内容
def gethtml(url):
    data = requests.get(url)
    return data.text
#正则匹配部分
def reurlstart(url):
    #os.remove('getcntv.txt')
    info = []
    text = gethtml(url)
    #央视的视频链接一般为 http://tv.cctv.com/年/月/日/乱七八糟.shtml
    #正则匹配式:[a-zA-z]+://tv.cctv.com/[0-9]*/[0-9]*/[0-9]*/.*"
    data = re.findall(r'[a-zA-z]+://tv.cctv.com/[0-9]*/[0-9]*/[0-9]*/.*"',text,re.I)
    for i in data:
        i = i.split('"')
            if i[0] != url:
                #这里要进行一次分割,因为原链接是 视频链接 + " + html
                info.append(i[0])
    #得到的数组有重复的链接,所以要去重
        dellist(info)
#去除重复链接
def dellist(list):
    list2 = []
    for i in list:
        if i not in list2:
            print i
            wfile(i)
                list2.append(i)
    return list2
#写文件
def wfile(text):
    f = open('getcntv.txt','a+')
    f.write(text + '\n')
    f.close()

a = raw_input('URL:')
reurlstart(a)

374_0.png