本文最后更新于: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服务实现对移动硬盘的写操作,然后再设置开机自动挂载移动硬盘。
sudo apt-get install ntfs-3g sudo mkdir /home/pi/share
sudo umount /dev/sda1 sudo mount -t ntfs-3g /dev/sda1 /home/pi/share sudo chmod 777 /home/pi/share sudo chmod 777 /home/pi
sudo vim /etc/fstab /dev/sda1 /home/pi/share ntfsdefaults0 0
2.1.2安装Samba sudo apt-get update sudo apt-get install samba samba-common-bin
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 [share] comment = samba share path = /home/pi/share valid user = pi root public = yes browseable = yes writable = yes
sudo smbpasswd -a pi sudo smbpasswd -e pi
sudo /etc/init.d/samba restart
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 sudo apt-get update sudo apt-get install minidlna
sudo vim /etc/minidlna.conf media_dir=A,/home/pi/share/Music media_dir=P,/home/pi/share/Picture media_dir=V,/home/pi/share/Video db_dir=/home/pi/share/dlnadb 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 sudo /etc/init.d/minidlna restart sudo /etc/init.d/minidlna status
sudo vim /etc/rc.local sudo /etc/init.d/minidlna restart
2.2.2 添加DLNA设备 点击我的电脑左上方的流媒体
系统会自动搜索到局域网中的支持DLNA的设备,点击添加,等待添加完成。
打开支持DLNA或者是流媒体播放的软件,就能看到树莓派中的流媒体文件。
2.3 下载机 2.3.1 安装transmission sudo apt-get update sudo apt-get install transmission-daemon
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" ,"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 sudo apt-get update sudo apt-get install aria2
sudo mkdir /etc/aria2 sudo touch /etc/aria2/aria2.session sudo vim /etc/aria2/aria2.conf
dir =/home/pi/share/Downloads disable-ipv6=true enable-rpc=true rpc-allow-origin-all=true rpc-listen-all=true continue =true input-file=/etc/aria2/aria2.session save-session=/etc/aria2/aria2.session max-concurrent-downloads=3
sudo aria2c --conf-path=/etc/aria2/aria2.conf sudo aria2c --conf-path=/etc/aria2/aria2.conf -D sudo vim /etc/rc.local sudo aria2c --conf-path=/etc/aria2/aria2.conf -D
2.3.2.2 安装appache sudo apt-get install apache2chmod 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执行文件。
@echo offecho Backuping D:\MyBlog\source\_posts--------->192 .168 .8 .106 \share\Backupxcopy "D:\MyBlog\source\_posts" "\\RASPBERRYPI\share\Backup" /e/I/d/h/r/yexit
其中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 from time import sleep class lcd1602 : LCD_CLEARDISPLAY= 0x01 LCD_RETURNHOME = 0x02 LCD_ENTRYMODESET= 0x04 LCD_DISPLAYCONTROL = 0x08 LCD_CURSORSHIFT = 0x10 LCD_FUNCTIONSET = 0x20 LCD_SETCGRAMADDR= 0x40 LCD_SETDDRAMADDR= 0x80 LCD_ENTRYRIGHT = 0x00 LCD_ENTRYLEFT = 0x02 LCD_ENTRYSHIFTINCREMENT = 0x01 LCD_ENTRYSHIFTDECREMENT = 0x00 LCD_DISPLAYON = 0x04 LCD_DISPLAYOFF = 0x00 LCD_CURSORON= 0x02 LCD_CURSOROFF = 0x00 LCD_BLINKON = 0x01 LCD_BLINKOFF= 0x00 LCD_DISPLAYMOVE = 0x08 LCD_CURSORMOVE = 0x00 LCD_DISPLAYMOVE = 0x08 LCD_CURSORMOVE = 0x00 LCD_MOVERIGHT = 0x04 LCD_MOVELEFT= 0x00 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 ):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 ) self.write4bits(0x32 ) self.write4bits(0x28 ) self.write4bits(0x0C ) self.write4bits(0x06 ) 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) self.clear()
def begin (self, cols, lines ): if (lines > 1 ): self.numlines = lines self.displayfunction |= self.LCD_2LINE self.currline = 0
def home (self ): self.write4bits(self.LCD_RETURNHOME) self.delayMicroseconds(3000 )
def clear (self ): self.write4bits(self.LCD_CLEARDISPLAY) self.delayMicroseconds(3000 )
def setCursor (self, col, row ): self.row_offsets = [ 0x00 , 0x40 , 0x14 , 0x54 ] if ( row > self.numlines ): row = self.numlines - 1 self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
def noDisplay (self ): """ Turn the display off (quickly) """ self.displaycontrol &= ~self.LCD_DISPLAYON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def display (self ):""" Turn the display on (quickly) """ self.displaycontrol |= self.LCD_DISPLAYON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noCursor (self ):""" Turns the underline cursor on/off """ self.displaycontrol &= ~self.LCD_CURSORON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def cursor (self ):""" Cursor On """ self.displaycontrol |= self.LCD_CURSORON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noBlink (self ):""" Turn on and off the blinking cursor """ self.displaycontrol &= ~self.LCD_BLINKON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noBlink (self ):""" Turn on and off the blinking cursor """ self.displaycontrol &= ~self.LCD_BLINKON self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def DisplayLeft (self ):""" These commands scroll the display without changing the RAM """ self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)
def scrollDisplayRight (self ):""" These commands scroll the display without changing the RAM """ self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT);
def leftToRight (self ):""" This is for text that flows Left to Right """ self.displaymode |= self.LCD_ENTRYLEFT self.write4bits(self.LCD_ENTRYMODESET | self.displaymode);
def rightToLeft (self ):""" This is for text that flows Right to Left """ self.displaymode &= ~self.LCD_ENTRYLEFT self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def autoscroll (self ):""" This will 'right justify' text from the cursor """ self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
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 ) 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()
def delayMicroseconds (self, microseconds ): seconds = microseconds / float (1000000 ) sleep(seconds)
def pulseEnable (self ): self.GPIO.output(self.pin_e, False ) self.delayMicroseconds(1 ) self.GPIO.output(self.pin_e, True ) self.delayMicroseconds(1 ) self.GPIO.output(self.pin_e, False ) self.delayMicroseconds(1 )
def message (self, text ):""" Send string to LCD、Newline wraps to second line""" for char in text:if char == '\n' : self.write4bits(0xC0 ) else : self.write4bits(ord (char),True )
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 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目录下
sudo vim /etc/rc.local sudo python /home/pi/1602/1602.py
3、爬虫服务器 3.1 Python源码示例 from urllib import requestimport jsonimport timefrom datetime import datetimefrom datetime import timedeltaimport pandas as pdfrom lxml import etreefrom tqdm import tqdmimport randomimport reimport 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 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' ] comments = []for item in data: comment = {'id' : item['id' ],'cityName' : item['cityName' ] if 'cityName' in item else '' , 'content' : item['content' ].replace('”' ,' ' ).replace('“' ,' ' ).replace(',' ,' ' ).replace(',' ,' ' ).replace('\n' , ' ' ), 'score' : item['score' ],'startTime' : item['startTime' ] } comments.append(comment)return commentsdef savetoCSV (): 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 ) start_time = datetime.strftime(start_time, '%Y-%m-%d %H:%M:%S' )
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' )
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吧。