树莓派3B+打造多媒体中心

本文最后更新于:September 10, 2018 pm

小七比较喜欢在宿舍和室友一起看电影或听音乐,且对画质和音质要求较高,一般都是观看1080P的蓝光REMUX电影(约30G一部)和听无损音质的音乐(30M一首),且观看设备较多(电视盒子、电脑、手机),再加上平时需要下载电影且自己有写博客的习惯,博客和一些其他的重要资料也需要备份,因此决定使用树莓派3B+、一块移动硬盘和一个路由器搭建一个宿舍多媒体中心来满足这些需求。


1、功能简介

1.1 Samba

Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通信协议,它为局域网内的不同计算机之间提供文件及打印机等资源的共享服务。

换言之,使用Samba可以在局域网内实现文件的共享操作,有些放在移动硬盘里面的文件需要用的时候就不用再插移动硬盘,在网上邻居处拷贝即可。

1.2 miniDLNA

DLNA的全称是DIGITAL LIVING NETWORK ALLIANCE(数字生活网络联盟),DLNA并不是创造技术,而是形成一种解决的方案,一种大家可以遵守的规范。

所以,其选择的各种技术和协议都是当前所应用很广泛的技术和协议。miniDLNA可以实现音乐视频图片的局域网跨设备共享,且目前大多数智能手机、平板和电视均支持DLNA协议,在树莓派上安装miniDLNA服务后即可让处在同一局域网下的设备能轻松访问到树莓派上的影音资源。

1.3 下载机

Transmission全称TransmissionBittorrent,由C开发而成(Mac OS上用的是Objective-C),硬件资源消耗极少,界面极度精简。支持包括Linux、BSD、Solaris、Mac OS X等多种操作系统,以及Networked Media Tank、WD MyBook、ReadyNAS、D-Link DNS-323 & CH3SNAS、Synology等多种设备。支持GTK+、命令行、Web等多种界面。

Aria2支持Http、FTP、磁力链接和BT下载,可以和Transimission互补。

1.4 自动备份

数据备份是一个好习惯,但是总是会有遗忘或者是疏漏的情况出现,因此我们可以利用树莓派来实现自动备份。首先可以创建powershell命令实现备份功能,再另存为bat脚本文件,最后利用windows自带的定时任务功能和linux的定时执行命令操作来实现文件自动备份到树莓派上的操作。

1.5 状态监控

作为长时间运行的多媒体中心,树莓派的运行状态不能忽视,因此我们可以使用LCD1602显示屏连接树莓派,显示一些必要的信息来监控它的运行状态。(CPU,GPU, RAM, IP, TIME)

2、安装操作

2.1 Samba

2.1.1 安装ntfs-3g

树莓派接上移动硬盘后,会自动挂载到/media目录下,但是由于我的硬盘是ntfs格式,在树莓系统下只能读不能写,因此我需要安装ntfs-3g服务实现对移动硬盘的写操作,然后再设置开机自动挂载移动硬盘。

1
2
3
4
5
sudo apt-get install ntfs-3g
#安装ntfs -3g服务

sudo mkdir /home/pi/share
#创建用于挂载移动硬盘的目录

1
2
3
4
5
6
7
8
9
10
11
12
sudo umount /dev/sda1
#有些系统会自动挂载,因此先使用umont命令取消挂载移动硬盘
#后面的/dev/sda1是硬盘在此系统中对应的编号,可以使用 df -h命令查看,或者直接使用硬盘名代替

sudo mount -t ntfs-3g /dev/sda1 /home/pi/share
#使用ntfs -3g挂载硬盘到指定目录

sudo chmod 777 /home/pi/share
#使用chmod命令赋予目录读写权限

sudo chmod 777 /home/pi
#目录的上级目录也需要赋予读写权限

1
2
3
4
5
6
7
8
9
10
11
sudo vim /etc/fstab
#编辑/etc/fstab文件实现开机自动挂载硬盘

#在文件的最后一行加入下列代码
/dev/sda1 /home/pi/share ntfsdefaults0 0
#第一列是挂载的硬盘设备名或者uuid
#第二列是挂载的目录
#第三列是硬盘的文件系统类型
#第四列是文件系统的参数,defaults表示同时具有rw, suid, dev, exec, auto, nouser, async等默认参数的设置
#第五列是能否被dump备份命令作用:dump是一个用来作为备份的命令。通常这个参数的值为0或者1,0表示不备份
#第六列是是否检验扇区:开机的过程中,系统默认会以fsck检验我们系统是否为完整(clean)。0表示不要检验

2.1.2安装Samba

1
2
3
4
5
6
sudo apt-get update
#首先更新一下系统源

sudo apt-get install samba samba-common-bin
#安装samba-common版本
#samba-common:这个套件则主要提供了 SAMBA 的主要设定档(smb.conf) 、 smb.conf 语法检验的测试程序 ( testparm )等等;

1
2
sudo vim /etc/samba/smb.conf
#编辑配置文件,在文件中加入下列内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
security = share
#开放security权限等级为share
#share---不需要提供用户名和密码。
#user----需要提供用户名和密码,而且身份验证由 samba server 负责。
#server--需要提供用户名和密码,可指定其他机器(winNT/2000/XP)或另一台 samba server作身份验证。
#domain--需要提供用户名和密码,指定winNT/2000/XP域服务器作身份验证。

[share]
#share为开启共享后的文件夹名
comment = samba share
#comment为备注,帮助理解这个共享文件夹
path = /home/pi/share
#path为共享的文件目录路径
valid user = pi root
#vaild users-----设定只有此名单内的用户才能访问共享资源(拒绝优先)(用户名/@组名),这里设置为pi和root两个
public = yes
#public----------是yes/否no公开共享,若为否则进行身份验证(只有当security = share 时此项才起作用)
browseable = yes
#browseable------是yes/否no在浏览资源中显示共享目录,若为否则必须指定共享路径才能存取
writable = yes
#writable--------是yes/否no不以只读方式共享当与read only发生冲突时,无视read only

1
2
3
4
5
6
7
8
9
10
11
12
sudo smbpasswd -a pi
#新建一个名为pi的用户,然后会提示输入两次密码
#smbpasswd命令的一些用法如下
#-a:向smbpasswd文件中添加用户;
#-c:指定samba的配置文件;
#-x:从smbpasswd文件中删除用户;
#-d:在smbpasswd文件中禁用指定的用户;
#-e:在smbpasswd文件中激活指定的用户;
#-n:将指定的用户的密码置空。

#设置完用户名和密码后输入下列命令激活用户
sudo smbpasswd -e pi

1
2
#然后重启samba服务即可生效
sudo /etc/init.d/samba restart

1
2
3
4
5
#最后还是要设置开机启动
sudo vim /etc/rc.local

#在下面添加如下代码
sudo /etc/init.d/samba restart

2.1.3添加网络映射

添加网络映射主要是方便访问,可以将共享的samba文件夹添加到我的电脑中。首先右键我的电脑,点击添加网络映射/Add a network location

输入共享的文件夹路径,然后命名,最后即可完成。

2.2 miniDLNA

2.2.1 安装miniDLNA

1
2
3
4
5
sudo apt-get update
#先更新一下安装源

sudo apt-get install minidlna
#安装minidlna

1
2
3
4
5
6
7
8
9
10
11
12
13
#安装完后编辑配置文件
sudo vim /etc/minidlna.conf

media_dir=A,/home/pi/share/Music
#A表示这个目录是存放音乐的,当minidlna读到配置文件时,它会自动加载这个目录下的音乐文件
media_dir=P,/home/pi/share/Picture
#P表示图片文件
media_dir=V,/home/pi/share/Video
#V表示视频文件
db_dir=/home/pi/share/dlnadb
#配置minidlna的数库数据的存放目录
log_dir=/home/pi/share/dlnalog
#配置日志目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#然后建立对应的文件夹并给予对应的权限
sudo mkdir /home/pi/share/Music
sudo mkdir /home/pi/share/Picture
sudo mkdir /home/pi/share/Video
sudo mkdir /home/pi/share/dlnadb
sudo mkdir /home/pi/share/dlnalog

sudo chmod 777 /home/pi/share/Music
sudo chmod 777 /home/pi/share/Picture
sudo chmod 777 /home/pi/share/Video
sudo chmod 777 /home/pi/share/dlnadb
sudo chmod 777 /home/pi/share/dlnalog

#使用下列命令重启dlna服务
sudo /etc/init.d/minidlna restart

#再使用下列命令查看dlna状态
sudo /etc/init.d/minidlna status

1
2
3
4
#最后修改开机启动文件
sudo vim /etc/rc.local
#在后面加入以下代码
sudo /etc/init.d/minidlna restart

2.2.2 添加DLNA设备

点击我的电脑左上方的流媒体

系统会自动搜索到局域网中的支持DLNA的设备,点击添加,等待添加完成。

打开支持DLNA或者是流媒体播放的软件,就能看到树莓派中的流媒体文件。

2.3 下载机

2.3.1 安装transmission

1
2
3
4
sudo apt-get update
#先更新一下安装源
sudo apt-get install transmission-daemon
#然后安装transmission

1
2
3
4
5
6
7
8
9
10
11
12
13
#创建目录用于存放下载文件
sudo mkdir /home/pi/share/Downloads/Incomplete
#存放未下载完成的文件
sudo mkdir /home/pi/share/Downloads/complete
#存放下载完成的文件

#更改文件所属组别
sudo chgrp debian-transmission /home/pi/share/Downloads/Incomplete
sudo chgrp debian-transmission /home/pi/share/Downloads/complete

#赋予文件夹权限
sudo chmod 777 /home/pi/share/Downloads/Incomplete
sudo chmod 777 /home/pi/share/Downloads/complete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#修改配置文件
sudo vim /etc/transmission-daemon/settings.json

#找到以下项进行修改
#已完成的下载目录
"download-dir": "/home/pi/share/Downloads/complete",
#未完成的下载目录
"incomplete-dir": "/home/pi/share/Downloads/Incomplete",
#允许Web访问的白名单地址,这里要根据自己的路由器实际IP地址进行修改
"rpc-whitelist": "192.168.8.*",
#登录的用户名
“rpc-username”: “yourname”,
#登录的密码
“rpc-password”: “yoursecretcode”,

#最后依次执行下面的两条命令完成重启服务
sudo service transmission-daemon reload
sudo service transmission-daemon restart

最后我们访问树莓派的IP再加上9091端口就能登录到下载界面。

2.3.2 安装Aria2

2.3.2.1 安装Aria2

1
2
3
4
sudo apt-get update
#更新一下安装源
sudo apt-get install aria2
#安装aria2

1
2
3
4
5
6
7
8
#在/etc目录下创建aria2目录用来存放配置文件:
sudo mkdir /etc/aria2

#创建空白的aria2.session文件:
sudo touch /etc/aria2/aria2.session

#创建配置文件
sudo vim /etc/aria2/aria2.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#在该文件中输入以下内容:

dir=/home/pi/share/Downloads
#设置文件下载的存放目录
disable-ipv6=true
#打开rpc的目的是为了给web管理端用
enable-rpc=true
rpc-allow-origin-all=true
rpc-listen-all=true
#rpc-listen-port=6800
continue=true
input-file=/etc/aria2/aria2.session
save-session=/etc/aria2/aria2.session
max-concurrent-downloads=3
#设置最大同时下载的任务数

1
2
3
4
5
6
7
8
9
10
11
12
#启动aria2
sudo aria2c --conf-path=/etc/aria2/aria2.conf

#如果没有提示任何错误信息,那就按ctrl+c停止上面的语句,转为后台运行:

sudo aria2c --conf-path=/etc/aria2/aria2.conf -D

#同时其此句写到开机启动中,编辑/etc/rc.local
sudo vim /etc/rc.local

#在文件的最后面添加这一行
sudo aria2c --conf-path=/etc/aria2/aria2.conf -D

2.3.2.2 安装appache

1
2
3
4
5
#安装appach
sudo apt-get install apache2

#修改/var/www/html的权限
chmod 777 /var/www/html

2.3.2.3 安装yaaw

https://github.com/binux/yaaw下载yaaw,点击右下角的Download Zip, 下载后将解压后的文件夹内容拷贝到/var/www/html文件夹下。这时在浏览器内输入树莓派的IP,如果出现以下页面,则表示已经正常工作了。

点击左上方的add就可以进行下载。

2.4 自动备份

2.4.1 创建自动执行文件

使用记事本新建一个文件,里面输入下列代码,然后保存并更改文件名后缀为bat执行文件。

1
2
3
4
@echo off
echo Backuping D:\MyBlog\source\_posts--------->192.168.8.106\share\Backup
xcopy "D:\MyBlog\source\_posts" "\\RASPBERRYPI\share\Backup" /e/I/d/h/r/y
exit

其中xcopy指令后两个路径分别为需要备份的文件夹路径和用于存放备份的文件夹路径,其余参数说明如下:

/e:拷贝所有子目录,包括空子目录;

/I: 如果目标文件或目录不存在且拷贝的文件数多于一,则假设目标为目录;

/d:只拷贝文件日期与在目标文件后的文件(即修改过的源文件)

/h:同时拷贝隐藏文件和系统文件

/r:拷贝并覆盖只读文件

/y: 复制文件审核设置(不显示已有文件覆盖确认)

以上参数可以根据需要添加,推荐都加上最好。

2.4.2 设置定时任务

然后我们打开”控制面板”—“计划任务”添加计划任务,计划任务里的执行目标为该批处理文件,设定在什么时候执行则由个人决定。

执行效果示例如下:

2.5 状态监控

按照针脚跳线连接好LCD1602和树莓派并调节好LCD1602的对比度,使用python编写代码,控制1602输出相关信息,具体代码如下:

将下面这个文件保存为lcd1602.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/python

#
# based on code from lrvick and LiquidCrystal
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
#

from time import sleep

class lcd1602:

# commands
LCD_CLEARDISPLAY= 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET= 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR= 0x40
LCD_SETDDRAMADDR= 0x80

# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00

# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON= 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF= 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00

# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT= 0x00

# flags for function set
LCD_8BITMODE= 0x10
LCD_4BITMODE= 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS= 0x04
LCD_5x8DOTS = 0x00


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def __init__(self, pin_rs=14, pin_e=15, pins_db=[17, 18, 27, 22], GPIO = None):
# Emulate the old behavior of using RPi.GPIO if we haven't been given
# an explicit GPIO interface to use
if not GPIO:
import RPi.GPIO as GPIO
self.GPIO = GPIO
self.pin_rs = pin_rs
self.pin_e = pin_e
self.pins_db = pins_db

self.GPIO.setmode(GPIO.BCM)
self.GPIO.setwarnings(False)
self.GPIO.setup(self.pin_e, GPIO.OUT)
self.GPIO.setup(self.pin_rs, GPIO.OUT)

for pin in self.pins_db:
self.GPIO.setup(pin, GPIO.OUT)

self.write4bits(0x33) # initialization
self.write4bits(0x32) # initialization
self.write4bits(0x28) # 2 line 5x7 matrix
self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
self.write4bits(0x06) # shift cursor right

self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF

self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
self.displayfunction |= self.LCD_2LINE

""" Initialize to default text direction (for romance languages) """
self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) # set the entry mode

self.clear()

1
2
3
4
5
6
def begin(self, cols, lines):

if (lines > 1):
self.numlines = lines
self.displayfunction |= self.LCD_2LINE
self.currline = 0

1
2
3
4
def home(self):

self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
self.delayMicroseconds(3000) # this command takes a long time!

1
2
3
4
def clear(self):

self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
self.delayMicroseconds(3000)# 3000 microsecond sleep, clearing the display takes a long time

1
2
3
4
5
6
7
8
def setCursor(self, col, row):

self.row_offsets = [ 0x00, 0x40, 0x14, 0x54 ]

if ( row > self.numlines ):
row = self.numlines - 1 # we count rows starting w/0

self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))

1
2
3
4
5
def noDisplay(self): 
""" Turn the display off (quickly) """

self.displaycontrol &= ~self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

1
2
3
4
5
def display(self):
""" Turn the display on (quickly) """

self.displaycontrol |= self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

1
2
3
4
5
def noCursor(self):
""" Turns the underline cursor on/off """

self.displaycontrol &= ~self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

1
2
3
4
5
def cursor(self):
""" Cursor On """

self.displaycontrol |= self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

1
2
3
4
5
def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

1
2
3
4
5
def noBlink(self):
""" Turn on and off the blinking cursor """

self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)

1
2
3
4
def DisplayLeft(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)

1
2
3
4
def scrollDisplayRight(self):
""" These commands scroll the display without changing the RAM """

self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);

1
2
3
4
5
def leftToRight(self):
""" This is for text that flows Left to Right """

self.displaymode |= self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);

1
2
3
4
def rightToLeft(self):
""" This is for text that flows Right to Left """
self.displaymode &= ~self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)

1
2
3
4
5
def autoscroll(self):
""" This will 'right justify' text from the cursor """

self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)

1
2
3
4
5
def noAutoscroll(self): 
""" This will 'left justify' text from the cursor """

self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def write4bits(self, bits, char_mode=False):
""" Send command to LCD """

self.delayMicroseconds(1000) # 1000 microsecond sleep

bits=bin(bits)[2:].zfill(8)

self.GPIO.output(self.pin_rs, char_mode)

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i], True)

self.pulseEnable()

for pin in self.pins_db:
self.GPIO.output(pin, False)

for i in range(4,8):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i-4], True)

self.pulseEnable()

1
2
3
def delayMicroseconds(self, microseconds):
seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
sleep(seconds)

1
2
3
4
5
6
7
def pulseEnable(self):
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, True)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # commands need > 37us to settle

1
2
3
4
5
6
7
8
def message(self, text):
""" Send string to LCD、Newline wraps to second line"""

for char in text:
if char == '\n':
self.write4bits(0xC0) # next line
else:
self.write4bits(ord(char),True)

1
2
3
4
5
if __name__ == '__main__':

lcd = lcd1602()
lcd.clear()
lcd.message("hello world!")

再将这个文件保存为1602.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/usr/bin/python

from lcd1602 import *
from datetime import *
import commands

def get_cpu_temp():
tmp = open('/sys/class/thermal/thermal_zone0/temp')
cpu = tmp.read()
tmp.close()
return '{:.2f}'.format( float(cpu)/1000 ) + ' C'

def get_gpu_temp():
tmp = commands.getoutput('vcgencmd measure_temp|awk -F= \'{print $2}\'').replace('\'C','')
gpu = float(tmp)
return '{:.2f}'.format( gpu ) + ' C'

def get_time_now():
return datetime.now().strftime('%H:%M:%S\n %Y-%m-%d')

def get_ip_info():
ip= commands.getoutput('ifconfig eth0 | grep inet | awk \'{ print $2 }\' | awk \'NR==1\'')
return 'Ethernet IP:\n' + ip

def get_mem_info():
total= commands.getoutput('free -m|grep Mem:|awk \'{print $2}\'')
free= commands.getoutput('free -m|grep Mem:|awk \'{print $4}\'')
return 'MEM:\n' + free +'/'+ total +'M'

lcd = lcd1602()
lcd.clear()

if __name__ == '__main__':

while(1):
lcd.clear()
lcd.message( get_ip_info() )
sleep(5)

lcd.clear()
lcd.message( get_time_now() )
sleep(5)

lcd.clear()
lcd.message( get_mem_info() )
sleep(5)

lcd.clear()
lcd.message( 'CPU: ' + get_cpu_temp()+'\n' )
lcd.message( 'GPU: ' + get_gpu_temp() )
sleep(5)

最后将两个文件保存到同一个目录下面,然后编辑文件设置开机启动即可让LCD1602循环显示信息。

我将这两个文件保存到/home/pi/1602目录下

1
2
3
4
#编辑配置文件
sudo vim /etc/rc.local
#将此命令添加到文件最后
sudo python /home/pi/1602/1602.py

3、爬虫服务器

3.1 Python源码示例

1
2
3
4
5
6
7
8
9
10
11
12
#encoding='UTF-8'
from urllib import request
import json
import time
from datetime import datetime
from datetime import timedelta
import pandas as pd
from lxml import etree
from tqdm import tqdm
import random
import re
import csv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 获取数据,根据url获取
def get_data(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36'
}
req = request.Request(url, headers=headers)
response = request.urlopen(req)
if response.getcode() == 200:
return response.read()
return None

# 处理数据
def parse_data(html):
data = json.loads(html)['cmts'] # 将str转换为json
comments = []
for item in data:
comment = {
'id': item['id'],
#'nickName': item['nickName'],
'cityName': item['cityName'] if 'cityName' in item else '', # 处理cityName不存在的情况
# 处理评论内容换行的情况,并且将逗号替换为空格
'content': item['content'].replace('”',' ').replace('“',' ').replace(',',' ').replace(',',' ').replace('\n', ' '),
'score': item['score'],
'startTime': item['startTime']
}
comments.append(comment)
return comments

# 存储数据,存储到文本文件
def savetoCSV():
#设置指定时间向前爬取评论数据或者从特定的时间段爬取评论
#start_time = '2015-05-12 02:40:34'
start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 获取当前时间,从当前时间向前获取
#设置爬取评论数据的截至时间
end_time = '2015-05-01 00:00:00'
while start_time > end_time:
url = 'http://m.maoyan.com/mmdb/comments/movie/248170.json?_v_=yes&offset=0&startTime=' + start_time.replace(' ', '%20')
html = None
'''
问题:当请求过于频繁时,服务器会拒绝连接,实际上是服务器的反爬虫策略
解决:1.在每个请求间增加延时0.1秒,尽量减少请求被拒绝
2.如果被拒绝,则0.5秒后重试
'''
try:
html = get_data(url)
except Exception as e:
time.sleep(0.5)
html = get_data(url)
else:
time.sleep(0.1)

comments = parse_data(html)
print(comments)
start_time = comments[14]['startTime'] # 获得末尾评论的时间
start_time = datetime.strptime(start_time, '%Y-%m-%d %H:%M:%S') + timedelta(seconds=-1) # 转换为datetime类型,减1秒,避免获取到重复数据
start_time = datetime.strftime(start_time, '%Y-%m-%d %H:%M:%S') # 转换为str

1
2
3
4
for item in comments:
with open('test3.csv', 'a', encoding='utf-8') as f:
f.write(str(item['id']) + ',' + item['startTime'].strip('[\'').split(' ')[0] + ',' + str(item['score']) + ',' + item['cityName'] + ',' + str(item['content']) + '\n')
#f.write(str(item['id'])+','+item['nickName'] + ',' + item['cityName'] + ',' + item['content'] + ',' + str(item['score'])+ ',' + item['startTime'] + '\n')


1
2
3
4
5
if __name__ == '__main__':
html = get_data('http://m.maoyan.com/mmdb/comments/movie/248170.json?_v_=yes&offset=0&startTime=2018-12-31%2022%3A25%3A03')
comments = parse_data(html)
print(comments)
savetoCSV()

3.2 效果展示

4、写在最后

重启之后就可以尽情地享用树莓派打造的多媒体中心了,虽然树莓派3B+只有USB2.0接口,但是只要搭配上百兆lan口的路由器,局域网内流畅观看40G左右大小的一部电影还是毫无问题的。

如果有更高的需求,还是建议上更好的路由器和NAS吧。