分类目录归档:python

给树莓派添加重启关机按钮

最近一段时间开始捣鼓树莓派了,弄的都是试验性质的。经常会出现些问题 导致连不上树莓派可能是卡死或者断网什么的,有没有显示器也不知道到底是什么情况。 没办法只有拔掉电源重启了。

后来想想长期这样弄也不是办法SD卡禁不起折腾啊,于是就想办法给它添加了个“关机和重启按钮”。

这里实现上用了GPIO接口,通过读取一个接口的高低状态然后调用 重启以及关机命令。

我的pi是B版v1。GPIO接口和v2稍微不一样。具体看下图 把代码的接口定义替换成对应的就行了

rasberrypi GPIO

下面这个两幅图更容易看

树莓派v1 GPIO接口定义 树莓派v2 GPIO接口定义

另外使用pin的编号有两种方式

  1. Board Pin 这种是自然排序的,重p1到p26
  2. BCM GPIO Broadcom的编号方法 (上图中的绿色方块部分GPIO*)

我在代码中使用的是 *BCM *。

这里用到了两个GPIO接口,7和17 你也可以自己修改下。 一个用来接收按键信号,另外一个驱动led显示状态

led有三个状态 长亮:正在重启, 闪动:正在关机, 不亮:等待状态。

面包板连接 树莓派重启面包板连接图
若你有杜邦线的话也可以不通过面包板连接,按钮那个GND的线也不是必须的,用手直接触摸 GPIO7 也能起到把这个电压拉低的效果

实现代码

使用方法

按一下按钮 系统进入重启状态倒计时10秒,在这段时间内你可以接着按一下切换到关机状态。 按第三下取消关机进入等待状态。这三种状态可通过按按钮不断切换。

参考

上拉电阻和下拉电阻

使用 RPI.GPIO 模块的输入(INPUT)功能

RPI.GPIO WIKI

使用python向服务器POST大文件

使用python向服务器POST大文件

python 对http操作有几个库 urllib 、 urllib2 还有httplib

httplib比较偏底层 一般情况下使用urllib和urllib2就行了

NOTICE

在python3中urllib与urllib2被分割合并为了 urllib.request, urllib.parse, and urllib.error

httplib重命名为 http.client

分析http协议

python的这几个库中并没有提供直接上传文件的接口 我们先看下普通浏览器是怎么上传文件的 这里我在本地创建简单php程序 若有提交文件,则打印出文件相关的信息。否则显示一个上传表单表单

这里推荐一个抓包工具fildder 可以很方便的抓取htttp数据,并且直观的显示

下面就是抓取到的内容

从第1-13行就是请求消息http头部的内容,然后下面有个空行 比较重要的几行是

请求消息(Request message)有以下几部分组成

  • 请求行(request line), 例如 GET /images/logo.png HTTP/1.1
  • 请求头(Request Headers) 比如上面的 Host: localhost、 Content-Length: 295
  • 空行
  • 消息主体 message body

NOTICE

请求行与请求头必须以结尾,空行只能有不能有空格什么的 在HTTP/1.1协议中,除了Host 所有的请求头都是可选的(当然若上传文件的话,就必须设置了Content-Length和Content-Type了, 不然服务器收不到数据的,虽然也能成功响应)

这里message body的类型是multipart/form-data;

boundary 是随机的内容每次请求都不一样, Content-Type为 multipart/form-data; 可同时传输多项数据,而这些数据就是通过 boundary分割开来的

每一项的数据都是’–‘+boundary+换行开始 ,然后是Content-Disposition: form-data;name=”表单项名”

若是文件的话 还有个filename 以及Content-Type,接下来一个空行

最后’–‘+boundary+’–‘+换行结束

到这里整个http请求就结束了

模拟提交数据

其实http协议就是字符串按照约定规则拼接到一起 然后服务器再来解析得到数据 所以我们自己直接使用socket也能发起了一个http请求

但是有了urllib2我们可以省很多事 只需“拼接”内容部分就行了

url 可以是一个链接或者Request对象 data 就是我们要“拼接的内容”

下面是运行后的输出结果

php能正常接收传输的文件了 但是这里有个问题 ,我们拼接数据的时候使用的是

直接把文件内容读到内存中去了,小文件还好,要是几百M上G的文件还用这种方法就不行了,这样会把你的内存吃干。

所以我们就需要弄个变通的方法,让它一块一块的发送数据,读一点发送一点。 这几个库并没有提供类似的方法实现这一个功能,所以就需要自己动手了。

首先介绍一个python的关键字 yield 关于介绍python yield的文章可以查看Python yield 使用浅析 可以通过它来实现一个生成器(generator) 来不断的读取文件数据,而且是只在我们需要的时候读取

然后我重写了 httplib 中 HTTPConnection.send(data)使它可以接收一个generator,从里面取数据然后发送 下面是原版HTTPConnection.send的源码

它支持文件类型File Object 或者是一个字符串

下面是个重新版本

当然若想实现完美的文件提交,还需要做个封装,下面是一个简单的实现,还有写不完善的地方,post数据只能传文件,打算做个python lib封装一下

现在有很多现成的第三方库比如 poster Requests 可以实现这些功能了,但是由于是第三方库需要用户手动安装,在一个我需要上传大文件时有个回调功能,这样就能显示进度了。 等运行稳定了会添加到kuaipan cli 里面,就可以摆脱poster依赖

参考资料

HTTP

python argparse模块bug:将版本信息输出到标准错误

今天打算把 kuaipan cli 编译成 二进制版本

kuaipan cli 使用的官方模块argparse解析命令行参数

下面这种方式,已经被官方废弃了,应该是为了解决 -v冲突的问题

后来修改为

于是写了个脚本自动编译,并且获取版本号

但是 $version 始终为空 ,单独执行 kuaipan.py -v是没问题的

运行环境 debian下是Python 2.7.3 ,window下是Python 2.7.6 都不行

然后怀疑是 argparse的问题

查看了下argparse模块的源码 版本号 是 1.1

问题出来知道了,这里默认的version action 把信息输出到了 stderr标准错误

所以在命令行中获取不到

已经有人提交了issue18920 以及path 不知道什么时候能发布出来

目前临时解决方法是:将标准错误stderr输出到stdout