2017/07这篇博文的目的是从头开始记录如何搭建一个家庭监控环境,那我这里会将思路与可能遇到的问题都一一说明,本篇博客十分适合电子,计算机,通信专业本科生的第一个团队合作项目,实现简单,没有什么代码需要自己写,都是利用已有的开源项目完成,未来的可扩展性丰富。所有涉及到的软件部分都会放在GitHub中。
注:每一天的材料部分都不会重复之前提到过的材料。行内代码部分会有灰色背景。
This is not just another simple howto, please make your own note and try to think about each and every sentences. Keep asking why and how. Furthermore, you may adjust the pace of learning to fit your own plan. Day1 to Day7 are 7 logically independent sections, which doesn’t mean that you need to finish Day1 in just one day.
花销:硬件部分摄像头和wifi模块基本上100RMB能搞定,至于VPS部分看大家个人的情况。
(2020-07-06)
3年过去了,感谢大家在此期间的阅读,点赞和引用。我也在去年底结束了人生中的第一份工作。这篇博文写在工作之前,里面记录的家庭监控是当初为了照顾生病需要长期住院的外公而开发的。还记得外公对我说的最后两个字是“工作”,现在也算还了一小部分愿。特别想在这再说一句,在今年疫情的大背景下,希望大家继续秉持自己的信念和初心,流水不争先,争其滔滔不绝。当然也许注意锻炼身体哈!我们学电子计算机的孩子就是容易长时间在电脑前久坐。
Day 1
材料
- 一个支持刷写 OpenWRT 的路由器,推荐 TP-link WR703N,原因价格便宜(某宝上二手仅需 30 RMB 左右),在下面的教程当中称其为 wifi 模块。
- 一台 Linux 系统电脑,教程使用 Ubuntu 系统。
- 一根网线,用于连接 wifi 模块和电脑。
思路:利用 wifi 模块构建局域网(简称 AP 模式)
- 这一步是所有后续的基础,目的在于熟悉 OpenWRT。OpenWRT 系统自带了一个部署在 192.168.1.1:80 上的网页服务器,Luci。它和日常路由器中的登录管理页面是同一个东西,通过它我们可以很方便得设置路由器的不同功能和参数。但在本项目中,我并不推荐使用 Luci 执行后续相关的操作。原因有二,其一它占据空间很大!我们选用的 TP-link WR703N 的 SquashFS 只有 4 MB,因此每一个 bit 都很关键,所以一个本质是 UI 的软件对于本项目的开发者没有太大的必要。其二,对于像我们这样抱着学习目的的开发者来说,图形化用户界面可能会导致一定程度的依赖性,Luci 能完成的东西越多,我们自己能掌握到的东西就越少。
- AP 模式是以 wifi 模块为路由器,使用 DHCP 协议动态分配 ip 给所有加入的设备。所以第二点就是熟悉计算机网络的最基本内容,如何以一个路由器的视角看局域网。首先路由器作为主角分配 ip,此时默认包括路由器在内的所有设备都在同一个网段当中。这一点虽然看似也一点不重要,但在实际操作中我多次因为没有考虑到两个通信的设备是否在同一网段中,而导致通信失败。问题出现后,我还在到处查看是不是网线没插好,电源是不是不稳定之类的问题。所以希望大家不会重蹈覆辙,再次强调一下,wifi 模块和电脑用网线直连时保证能通信的大前提是:电脑 ip 所处的网段必须和 wifi 模块相同!
步骤
- 刷机。向 wifi 模块刷入不死引导以及 OpenWRT,具体步骤请看我的另一篇博文《OpenWRT刷机入门》。OpenWRT 官方给出 15.05 版本的针对 TP-Link WR703N 的固件可以在官网的这个页面找到,在网页里搜索关键字 703,然后你就可以发现名为 openwrt-15.05-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin 的官方固件。有了官方固件之后就继续参照《OpenWRT刷机入门》继续完成刷机!
- wifi 模块连电脑。用网线将电脑和 wifi 模块连接起来,设置电脑的ip和子网掩码为192.168.1.2/24。这样就保证电脑和 wifi 模块在同一网段下(因为 OpenWRT 默认的 ip 网段就是 192.168.1.XXX,如果之前有更改过默认的 ip 记得给电脑也配上同网段的 ip 即可),可以通过网线直接通信。Ubuntu 系统设置 ip 很简单,在插上网线后,电脑的网线接口(RJ45口)的数据灯闪烁就代表链接成功,接着在 Ubuntu 系统设置->网络中找到有线连接,修改 ipv4 选项卡下面的 ip 即可,更加具体的操作可以参考这里。
- 登录 OpenWRT 系统。Ubuntu 电脑打开 terminal,快捷键是
ctrl+alt+t
。如果已经用 ssh 命令登录过 OpenWRT 系统的就直接ssh root@192.168.1.1
(OpenWRT 刷机后默认的 ip 为 192.168.1.1),然后输入密码即可。如果是第一次登录 OpenWRT 系统,那么需要先telnet 192.168.1.1
用不加密方式登录系统,登录之后键入passwd
命令给 root 用户设置密码,设置好密码之后就必须要用 ssh 的方式登录。这一步使用 ssh 方式登录是为了给我们未来客制化的 wifi 模块提供多一层的安全保障,毕竟没有密码的根用户对于 Linux 而言是极其危险的。 - 使能 wifi。利用
cd /etc/config/
命令进入到 /etc/config/ 目录下,通过ls -altF
查看这个目录下的所有文件,我们使能 wifi 功能需要操作到的文件是 wireless。这是一个默认存在于 OpenWRT 文件系统中的重要配置文件。直接vim wireless
开始编辑。vim 是一款历史久远的命令行文本编辑器,里面的操作习惯和我们当下主流的编辑器相差甚远,需要一定时间的习惯和适应,如果对 vim 还不太熟悉的同学,我推荐在这里可以先暂停一下本项目进度,学习台湾同学编写一篇 vim 学习文档。vim 很难一下子掌握,但是我们不得不用它,因为在 TP-link WR703N 的 OpenWRT 中并没有给我们提供其他更好的编辑器。还有一个原因,它虽然“老”,但是特别优秀,快捷键的设置考虑到了方方面面,简而言之就是开发者的利器!了解它的基本内容对于嵌入式开发工作大有裨益。在看台湾同学的文章时,如果你觉得已经知道怎么在 vim 当中编写一个文档,那就回过来继续我们的教程吧。编辑 wireless 的内容其实很简单,里面有一行 option disabled “1”,我们所有要做的内容就是把它删除。除此之外,你还可以在 wifi-iface 部分看到我们的 AP 模式下默认的 ssid 和登录密码。如果需要更换一个具有个性的 ssid 和自己专属的登陆密码也只需要在这里修改即可。保存退出之后,用wifi
命令重新启动 wifi 功能,不久之后你就可以在电脑上搜索到一个名字是 OpenWRT 的 wifi 热点啦!恭喜,这是我们跨向成功的第一小步! - 用你手上的设备去连接这个热点试试吧!连上之后就代表第一天的内容结束了!
进阶
如果你是一名和我一样好奇心很重而且十分谨慎的开发者,并且觉得有必要粗浅了解 /etc/config/wireless 里存在的众多陌生设置,那么请看官方的英文文档!This could not harm you. Read it, my geek friend.
Day 2
材料
- 客制化OpenWRT固件工具:ImageBuilder,单击此处下载。解压在你喜欢的本地目录当中,我们称解压之后的ImageBuilder的目录为A目录,里面应该包含有:include, packages, scripts, target等等的目录以及.config, .targetinfo, Makefile, rules.mk等文件。A目录就是我们之后经常要在里面进行客制化OpenWRT的场所了。
- 支持mjpg格式输出的摄像头一枚,某宝上可以买到,40rmb左右。另外如果自己家有老的摄像头也可以拿来看看是不是支持mjpg输出。请看这个博文,学习一下如何用linux查看usb摄像头的基本信息,看看你的老摄像头是不是支持mjpg。这里必需要支持mjpg的原因是,首先jpg格式的图片是压缩过的图片,用的压缩算法又很经典,所以用mjpg传输图像要省流量,但是mjpg的压缩是需要很大计算量的!所以如果摄像头不支持mjpg的输出,只能靠wifi模块的CPU去进行格式转换,那就呵呵了,算死这个CPU,真的会算爆它的,因为我们选用的设备额定工作温度为0到40摄氏度。所以安全起见,实在没有mjpg的摄像头,那还是先停一下实战,买一个再说。
思路:在局域网中开启mjpg-streamer服务,并用其他加入该局域网的设备查看live video
- Mjpg-Streamer是一个开源项目,其基本功能是从一个uvc内核摄像头读取内容,然后将它推送到本地的8080端口上面。就是一个本地的视频服务器。它的项目网站在这里。OpenWRT的软件源中也已经对它有了移植,所以我们只需要从OpenWRT的官方网站上找到对应15.05版本OpenWRT系统的Mjpg-Streamer,然后下载安装即可。除此之外还需要一些其他的软件包去支持它的运行:kmod-usb-core, kmod-usb2, kmod-video-core, kmod-video-uvc, libpthread, libjpeg。前4个是linux的系统内核文件,相当于usb接口和摄像头的驱动;后2个是库文件,用与提供多线程和jpeg图片格式支持。
- 在第一天的内容当中提到过,由于这次选用的wifi模块的Flash(SquashFS)特别小!所以我们在安装Mjpg-Streamer的方法会很特别,不会是用OpenWRT默认的opkg这款软件进行安装下载,因为opkg的安装方式会消耗很多不必要的Flash空间,其直接结果就是装了几个额外的软件之后就没有剩余空间。所以我们采用客制化OpenWRT固件的方式,将需要的软件直接写到OpenWRT的固件当中,这样极其节省空间,而且还可以删去和本次项目没有关系的一些默认安装的软件,以达到系统精简的目的。
步骤
- 客制化OpenWRT固件。请先看我的这篇博文,去大致了解一下客制化固件,里面有推荐官方的wiki文档和其他一些准备内容,记得看完之后再接下去操作!如上所述。为了安装mjpg-streamer和之后的一些内容,我们需要将一些不需要的软件包删除,并安装必要的包。首先在本地电脑上打开terminal,然后
cd A/
,进入到A目录下。输入make image PROFILE=TLWR703 PACKAGES="-ppp -ppp-mod-pppoe -kmod-ppp -kmod-pppoe -kmod-pppox -kmod-nf-ipt6 -kmod-nf-contrack6 -kmod-ipv6 -ip6tables -odhcp6c -libip6tc -kmod-ipv6 -firewall -iptables -odhcpc -kmod-ipt-conntrack -kmod-ipt-core -kmod-ipt-nat -kmod-nf-conntrack -kmod-nf-ipt -kmod-nf-nat -kmod-nf-nathelper -uhttpd -uhttpd-mod-ubus kmod-video-core kmod-video-uvc libpthread libjpeg mjpg-streamer"
,之后程序就会自动进行客制化固件的过程了,视网络情况不同,客制化的花费时间也不同,我这里用中国移动的20MB宽带几分钟就完成了。至于命令为什么这么写,就在官方wiki中有解释,所以这部分基础内容不重复了,再强调一下为了扎实的前进,花时间去看一下我的博文和里面所提到的wiki。值得注意的是在ImageBuilder当中默认的软件里就不带luci,所以我们不用额外删除它咯!当然Day 1当中提到的官方固件里面是默认包括luci的。 - 刷机。将第一步当中A目录下的bin/ar71xx/下生成的固件,‘openwrt-15.05-ar71xx-generic-tl-wr703n-v1-squashfs-factory’,刷入我们的wifi模块,方法就是第一天中提到的刷机方式,《OpenWRT刷机入门》。这里可能会有疑问,为什么不一步到位直接让我们刷最终版本的固件呢?因为重复的练习,会让我们更加清楚自己在做什么。毕竟这篇博文的目的不仅仅是一篇HowTo,更加重要的是对问题的理解和处理问题的方式。好了这里就提一个新的需要注意的细节,在《OpenWRT刷机入门》的初级办法当中我们实际上用的
sysupgrade /tmp/openwrt-15.05.1-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin
这条命令进行刷机,那有心的小伙伴也许会有担心说我们Day 1当中更改了一下系统的设置,刷机之后这个设置还会保留吗?答案:会保留。在sysupgrade命令当中如果加入-n这个选项,那么一些的设置都会被reset,所以当我们发现自己改着改着系统不知道哪里被玩坏了之后,请记得在刷机的时候用带n选项的sysupgrade就可以了,这里给一个例子:sysupgrade -n /tmp/openwrt-15.05.1-ar71xx-generic-tl-wr703n-v1-squashfs-factory.bin
。所以,我们默认是保留设置的,Day 1当中已经给OpenWRT的root用户设置了密码,开启了ssh登录方式,以及AP模式,在刷机完成之后,这一切都会被保留,是不是很赞! - 将用户设备连入wifi模块提供的热点。用手机或者电脑连接,wifi模块的热点中。这样我们的用户设备会自动的被分配到一个ip,这个ip和wifi模块的ip属于同一个网段。我们假设是用电脑连接的,打开terminal,用
ssh root@192.168.1.1
链接到wifi模块。如果做到这里你发现搜不到wifi模块的热点,不用着急,我们这里的目的只是为了取得wifi模块的控制,所以像Day 1当中那样用有线方式连接也完全没问题,连上之后再去查找问题所在吧。 - 启动mjpg-streamer服务。用
vim /etc/config/mjpg-streamer
修改mjpg-streamer配置文件,找到里面的enabled设置,将0改为1即可。然后记得看一下这个配置文件里面的其他内容,都是很直白的内容,注意fps,led是可以删除的设置内容,目前不需要指定帧率和led灯的只是状态。记住默认的帐号密码和端口之后保存退出。然后启动服务:/etc/init.d/mjpg-streamer start
,以及确保OpenWRT开机自启动/etc/init.d/mjpg-streamer enable
。 - 将准备好的mjpg摄像头插到wifi模块的usb接口上。
- 电脑上打开浏览器,网址栏输入192.168.1.1:8080。默认mjpg-streamer的服务器是架设在8080端口上的。你就可以看到实时的监控画面咯!恭喜!
进阶
信息论里有一个基本的常识就是,从单一信源获得信息的时候必将会有信息的丢失,说成白话就是咱们听老师上课绝对不会全部记住老师讲了什么。所以我们每次的进阶内容还是很推荐大家阅读的,从多个途径对同一主题了解,事倍功倍。
第二天的进阶内容是让你熟悉一下mjpg-streamer在OpenWRT中的使用。请自己发现它里面补充说明的内容哦!因为我也是参照它学习的呢!
学有余力的geek们,可以看一下关于我们wifi模块的一些硬件信息:在这里,这里,还有这里。
Day 3
材料
无
思路:wifi模块加入wifi热点(简称STA模式)
- 因为最终我们的网络摄像头会部署在一个有wifi的环境当中,比如家里,办公室,等等。所以我们必须了解如何将wifi模块连入这些热点当中。其实有心的同学在第一天学习AP模式的时候看掉了进阶里面提到的/etc/config/wireless设置的话,对接下来我们需要完成的任务就不至于太陌生了。
- 由于我们的wifi模块可以使用有线连接,也可以无线,无线又可以分成AP与STA,当然所以对于每一种接入模式我们都需要在网卡上定义一个逻辑的网络接口,用于区分彼此。每一个逻辑网络接口中会定义这个网络接口的ip的分配方式,使用的物理接口,等等。这是OpenWRT网络设置的核心部分,具体的文件就是/etc/config/network。可见/etc/config/这个目录底下就是专门存放这种软件的设置文件,之后我们还会学习到一个linux命令专门用来修改这个目录底下的文件。所以想要连接wifi那就必须先在network这个配置文件里面创建一个逻辑网络接口,并且标明这个网络接口的ip,dns之类的都是通过dhcp分配的,因为一般我们遇到的wifi热点都是用DHCP的,所以这里就不考虑特殊情况了。如果你的实验环境要求wifi热点的ip是静态的,那请看今天进阶部分的内容,会给一些参考资料供研究。
步骤
-
ssh连接wifi模块。当然我们这里选择用网线比较方便,因为如果用AP的话,等一下由于要更改wireless的设置,会重启wifi,这样AP会在重启的时候自动断掉,这里推荐用有线连接。
-
修改wireless。用
vim /etc/config/wireless
进入编辑界面,在最下面加入(其实在哪加都一样,只要是自成一段就好。你可以放在中间的已有段落后面)config wifi-iface station option device radio0 option network wwan option mode sta option ssid 你家的ssid option encryption 对应的加密方式一般都是psk,psk2或wep option key wifi密码
wifi-iface后面跟的station是我们给这个wifi-iface小节取得名字,方便以后修改。里面根据自家情况需要变化的部分是ssid,encryption和key。其中不太明显的是encryption,加密方式。如果自己家新买无线路由器的时候有配置过路由器的同学会知道,wifi密码的加密方式也是分种类的,同一个字符串,比如‘12345678’,在不同的加密方式下面会有不同的验证密码的手段。一般无线路由器里面的加密方式会选用WPA或者WPA2又或是WEP。所以WPA对应的encryption是psk,WPA2对应的是psk2,WEP对应的是wep。除了这个各家各情况的三个部分,还有一个network,我们给的值是wwan,这就是思路里面提到的逻辑网络接口。我们在下面一步会在/etc/config/network中写明这个接口,这里的wwan也是个名字,我们称接下来新建的逻辑网络接口名叫wwan。
- 添加逻辑网络接口wwan。之前说了这么高大上的逻辑网络接口,又是核心咯,又是关键咯,其实设置起来超级超级简单。用
vim /etc/config/network
打开编辑。同样在最下面,或者中间的某处添加:config interface 'wwan' option proto 'dhcp'
这样一来这个wwan逻辑接口就会调用OpenWRT里由busybox这款软件提供的udhcpc命令去接收并且设置自己的ip辣。
-
重启wifi。
wifi down
然后再wifi
。之后使用ifconfig
看一下各个网卡物理接口的具体情况,找到wlan0这个网卡接口,注意哦,这里不是逻辑接口了!而是实实在在的网卡!如果看到inet addr:192.168.0.10 Bcast:192.168.0.255 Mask:255.255.255.0这三个字段(ip,广播地址,子网掩码),你就可以确定已经连上wifi热点辣! -
用同样连上这个热点的手机,打开浏览器,网址栏输入你的wifi模块的ip:8080,就实现了在本地局域网里查看摄像头的视频咯,不用再连上wifi模块提供的热点辣。比如我的wifi模块ip是192.168.0.10,那我就在网址栏里输入192.168.0.10:8080。不连wifi模块自己的OpenWRT热点,好处就是能用手机看摄像头的视频,又能聊微信。酷吧!下一个大目标就是想办法把我们假设的摄像头视频服务推到Internet上面,实现我在哪上网都能看到摄像头视频!
进阶
这里就是关于network这个配置文件的说明。
Day 4
材料
- ImageBuilder。为了实现wifi的检测功能,我们需要安装一个额外的程序包,wireless-tools,给客制化的OpenWRT。
思路:同时开启AP与STA模式
- 细心的朋友可能已经发现在Day3的内容当中,我们在将wifi模块连到一个热点上的同时,OpenWRT这个wifi模块本身的热点也会同时存在,所以我们已经把同时开启AP和STA的方法带到过了,这里着重提出一些细节上的问题。在此之前我想解释一下开启AP和STA的意图,当我们最后做完成品,这个带摄像头的wifi模块很可能会被放在天花板的角上或者一些平时够不到的地方,这样能保证镜头的视野。所以在这个时候如果我们相对wifi模块做一些更改的时候总不可能搬个梯子连着把网线连上去。于是乎AP模式就很有存在的必要了。那可能又有同学会问,我开着STA模式,不同样也可以ssh到wifi模块么!对的,没错,AP模式的作用可以被STA代替,但是如果家里的无线路由器不能正常工作了,或者改了一下密码,那STA模式不就会因为没有跟上它修改的新密码而失效。所以,说到底AP模式就是一个fail safe。一个方便我们操作的fail safe。
- 一个棘手的问题,如果真的STA模式瘫痪了,可能原因有很多,最简单的就是wifi热点的密码换了。那么会有一个很尴尬的结果,AP模式跟着失效。我的理解就是如果wireless当中的设置错误,wifi命令就会一直停在错误位置。因为没有查到wifi命令的帮助文件,所以只是个猜测。那如何保证我们的AP模式一直存在呢?找到的一个替代解决方案,它的思路是先把只有AP模式的wireless文件以及AP+STA模式的wireless文件保存在OpenWRT内部,默认的wireless也是这个AP+STA的设置。当每次开机的时候检测是否有连上wifi热点,即STA模式是否工作正常,如果正常那AP模式也就自然没有问题,如果工作异常,它会自动将wireless的内容换作只有AP模式的配置。相当于发现STA模式不好使的时候,断一下wifi模块的电源,然后等它重启后的自动检测。这算是解决这个问题的一个很简单的思路,在下面步骤这节会具体实现。
步骤
- 保存只有AP与AP+STA两种配置的wireless。我们首先将Day3当中的AP+STA的wireless通过
cp /etc/config/wireless /etc/config/wireless.ap+sta
保存到/etc/config/这个目录下,文件名叫wireless.ap+sta。内容如下config wifi-device 'radio0' option type 'mac80211' option hwmode '11g' option path 'platform/ar933x_wmac' option htmode 'HT20' option channel 'auto' config wifi-iface option device 'radio0' option network 'lan' option mode 'ap' option ssid 'OpenWrt' option encryption 'none' config wifi-iface 'station' option device 'radio0' option network 'wwan' option mode 'sta' option ssid 'some_ssid' option key 'some_key' option encryption 'some_encryption'
接下来用vim /etc/config/wireless
编辑,把最后station这个小节的config删除。再将这个AP only的设置方案保存到同一个目录下cp /etc/config/wireless /etc/config/wireless.ap-only
。内容如下
```
config wifi-device ‘radio0’
option type ‘mac80211’
option hwmode ‘11g’
option path ‘platform/ar933x_wmac’
option htmode ‘HT20’
option channel ‘auto’
config wifi-iface
option device 'radio0'
option network 'lan'
option mode 'ap'
option ssid 'OpenWrt'
option encryption 'none'
```
- 创建开机自动检测脚本。
cd /usr/bin/
,这个目录是默认属于系统环境目录,里面的程序可以自动被linux系统搜索到,然后touch reboot_ap_sta_detect.sh
新建一个脚本文件。用vim去编辑它,内容是:TIMEOUT=30 SLEEP=3 sta_err=0 while [ $(iwconfig | grep -c "ESSID:off") -ge 1 ]; do let sta_err=$sta_err+1 if [ $((sta_err * SLEEP)) -ge $TIMEOUT ]; then cp /etc/config/wireless.ap-only /etc/config/wireless wifi up break fi sleep $SLEEP done
这就是我们博文开篇提到的第一处写代码的部分咯,一个很简单的linux脚本,while循环内部每隔3秒去检测是否有wifi热点的连接,30秒之后还是没有检测到那就替换wireless为wireless.ap-only的设置。之后用chmod +x reboot_ap_sta_detect.sh
给这个脚本可执行的权限。然后在系统的开机启动文件当中把这个脚本添加进去,vim /etc/rc.local
,在exit 0这行之前加一行,内容是:reboot_ap_sta_detect.sh > /dev/null。值得注意的是,脚本里用于检测wifi状态的iwconfig程序,不在默认的客制化OpenWRT当中,所以称此机会回顾一下如何自定义OpenWRT固件吧。
3. 自定义固件与刷机。将wireless-tools,这款程序刷到固件内,然后将新的固件刷机回来。具体步骤请看Day2!这里只给出一个自定义固件的make语句:make image PROFILE=TLWR703 PACKAGES="-ppp -ppp-mod-pppoe -kmod-ppp -kmod-pppoe -kmod-pppox -kmod-nf-ipt6 -kmod-nf-contrack6 -kmod-ipv6 -ip6tables -odhcp6c -libip6tc -kmod-ipv6 -firewall -iptables -odhcpc -kmod-ipt-conntrack -kmod-ipt-core -kmod-ipt-nat -kmod-nf-conntrack -kmod-nf-ipt -kmod-nf-nat -kmod-nf-nathelper -uhttpd -uhttpd-mod-ubus kmod-video-core kmod-video-uvc libpthread libjpeg mjpg-streamer wireless-tools"
。以及,注意用sysupgrade刷机的时候切忌不要加上-n这个属性,不然我们辛辛苦苦的设置文件就全没了!
4. 刷完机回来你会发现刚刚辛苦写的脚本不见了!是的,这就是刷机的作用。哈哈,这里故意放个小坑,就是为了再让你熟悉一次如何给OpenWRT添加一个开机自启动的脚本文件。所以重复一下第二步吧!然后用cp /etc/config/wireless.ap+sta /etc/config/wireless
把AP+STA模式的配置文件拷回去(默认不用的,因为刷机的时候不加-n属性就会保留所有之前的配置,这里保险起见加了这么一句),再用vim /etc/config/wireless
故意把station部分的ssid改错,然后断电重启一下,看看这下我们的脚本是否会提供给我们一个AP呢!恭喜,今天的内容到这里结束辣!所有的配置文件啊脚本啊,都在GitHub当中。
进阶
如果不熟悉Linux脚本的同学,可以以我们这个简单的脚本为例学习一下。这里是grep程序的用法,这里是if以及while里面条件判断语句的用法。对于Linux的完整学习还推荐台湾作家蔡德明的《鸟哥的私房菜》,特别好,可惜有些内容有点旧了,毕竟这个行业发展迅速。
Day 5
材料
无
思路:解决如何将本地的live video服务推送到Internet中,实现任意网络位置都能查看live video
- 首先不管是AP还是STA模式,我们的live video都仅仅是一个本地的http服务器,只有内网的用户才能访问到。没有公网ip的参与,我们是无法将live video放到Internet上的。我们最多能做的是,在入户网线的ip上做一个端口映射,将它的8080端口绑定到我们wifi模块ip的8080端口上,这样只要是用一个通信运营商的子网内部都可以访问到了,根据我大学好友所说,现在通信运营商布网的时候基本上都是一个住宅小区一个子网,很可能小区外面的同一个运营商的用户也访问不了。如果你想看一下自己的入户网线是不是在一个子网里面(基本一定是),可以在进户线连的路由器`看一下ip,如果是10.XXX.XXX.XXX或者192.168.XXX.XXX那就是在一个子网里头了。
- 所以确定需要一个公网ip的参与,租一个自己的VPS,买一个域名,自己的网站搞起!原先我想先学习一下mjpg-streamer的写法,在wifi模块上用C语言实现一个客户端,在VPS上用Java实现一个服务器,视频7/24有wifi模块推送到VPS上,然后在VPS上实现存储和响应查看请求。但是由于客观的需求,时间限制,和一个人的能力有限,这个方案被排除了。之后搜索了其他的内网穿透方案,发现一个很成熟的ngrok。它已经发展到2.0版本了,只可惜2.0是商用要钱。但是之前的版本还是放在github上供我们研究使用的。另外OpenWRT论坛上对ngrok的支持早就有大神实现了,所以水到渠成,决定采用ngrok。
步骤
- 租用VPS。考虑到最后成品的服务器需要接受 wifi 模块的实时画面,所以一个假设在本地的服务器是最佳的选择。国内知名度最高的应该是阿里云,如果觉得价格略高,则可以选择其他服务商。
- 购买域名。这里我们可以想办法省钱,阿里旗下的万网是一个很不错的购买域名的平台,它上面时不时有优惠活动可以几块前买一个一年的域名。不过要注意的是,国内域名的购买是需要实名认证的,这个过程可能花半天到1天不等,所以决定要自己搭服务器之后就立马去买域名吧。然后需要将域名和VPS的ip绑定。由于VPS商家不同,绑定的具体方式也不同,所以这里需要我们自行搜索一下VPS和域名绑定过程。
- 搭建ngrok服务器端。租用好服务器之后需要在上面做一些基本的学习工作,其实具体的操作也就是ssh啊,设置一下防火墙呀,之类的。可以参考我的服务器软件安装记录,里面写了如何搭建ngrok的服务器端。服务器端生成之后,就直接在服务器上跑起来吧!推荐在本地电脑也安装go语言,然后搭建ngrok服务器完成之后可以用go语言在本地计算机随便开一个http服务器,名字可以脚httpserver.go,内容如下
运行起来,然后从VPS上将生成的ngrok客户端用package main import "net/http" func main() { http.HandleFunc("/", hello) http.ListenAndServe(":8080", nil) } func hello(w http.ResponseWriter, r *http.Request) { w.Write([]byte("hello!")) }
scp admin_name@VPS_ip:/directory_to_ngrok_linux_client /usr/bin/
下载到本地/usr/bin/目录,之后可以根据我的博文里推荐的文章,去将本地的go语言http服务器推送到VPS上,如果成功的话,恭喜!今天的内容完成辣!你拥有了一个实现内网穿透的服务器!
进阶
虽然今天的步骤很短,那是因为大多数都是直接推荐了别的大神写的博文,实际上今天的工作量不小,所以请耐心完成基本部分,进阶内容为空。
Day 6
材料
思路:wifi模块中搭建Ngrok客户端
- 在上一天中,我们跟随leocode的教程生成过一个给Linux系统使用的ngrok的客户端版本,可是它太大,有11M多,而我又找到一个大神用C语言写好的版本,最后才52.7kb。所以长远考虑,选择使用c语言版本的。而且这个版本的使用和编译都相当简单。
步骤
- 编译ngrokc。具体步骤请看原作者的简书,或者github。最后我们会得到一个名字是ngrokc的可执行文件。
- 重新客制化OpenWRT固件,安装ngrokc的支持程序。ngrokc的支持程序有两个:libstdcpp和libopenssl。很不凑巧,这两个支持库也很大,所以需要客制化固件,而不能用opkg安装。具体的安装指令是
make image PROFILE=TLWR703 PACKAGES="-ppp -ppp-mod-pppoe -kmod-ppp -kmod-pppoe -kmod-pppox -kmod-nf-ipt6 -kmod-nf-contrack6 -kmod-ipv6 -ip6tables -odhcp6c -libip6tc -kmod-ipv6 -firewall -iptables -odhcpc -kmod-ipt-conntrack -kmod-ipt-core -kmod-ipt-nat -kmod-nf-conntrack -kmod-nf-ipt -kmod-nf-nat -kmod-nf-nathelper -uhttpd -uhttpd-mod-ubus kmod-video-core kmod-video-uvc libpthread libjpeg mjpg-streamer wireless-tools libstdcpp libopenssl
。抱歉辣,又要让刷机。没有一次性说明的原因就是希望学习曲线不会太陡。 - 连接wifi热点。刷好我们这个最后版本的OpenWRT客制化系统之后,要像之前那样让它连接到家里的wifi热点,这样才能通过Internet连接到我们先前租的VPS。
- 上传ngrokc到wifi模块。用
scp 存放ngrokc的目录/ngrokc root@192.168.1.1:/usr/bin/
将ngrokc传到wifi模块的/usr/bin/目录下,这样OpenWRT系统默认就可以找到它了。 - 开启ngrokc。运行命令
ngrokc -SER[Shost:ngrok.你的域名,Sport:Day5中定义的http端口] -AddTun[Type:http,Lhost:127.0.0.1,Lport:8080,Sdname:自定义的次级域名]
就可以在wifi模块上开启ngrok客户端。到此为止,所有的ngrok相关的设置就结束了!恭喜,你已经可以在任意一台设备的浏览器中输入“你定义的域名:你定义的端口”去访问这个摄像头了!
进阶
做到这里我们的项目实质部分已经结束,最后都是细节的整理,怎样让它easy to use。所以这里我们需要好好整理一下自己的笔记,看看这几天的过程是如何的。今天的进阶内容就是复习开始以来到现在所有做过的工作,特别是今天的内容,称热打铁,好好研读dosgo的github。
Day 7
材料
无
思路:wifi模块中增加简化使用的脚本
- 在Day4中,我们创建了一个开机自动启动的脚本检测STA模式是否工作正常,如果不正常则替换为AP模式,然后我们连上这个AP去校准STA的设置。同样的,我们希望正常情况下,如果STA工作无误,那么我们要保证ngrokc也同时运行,所以类似的写一个开机自启动的脚本放在我们之前那个reboot_ap_sta_detect.sh脚本后面启动。
- 另外一个很头疼的事情就是STA的设置,要人工查看每个需要连接的wifi热点是什么ssid,什么加密方式,哪个信道。其实我们用一个叫做iwlist的程序就可以把这些信息全部扫描出来,实现自动提取。具体的请看这篇帖子。griguolcomerranas同学在帖子中写了一个脚本实现了自动提取的功能。感谢大神的无私奉献!
步骤
-
确保wifi模块上已经完成了Day4的任务,以及刷上了Day6中最后一个客制化版本的OpenWRT。
-
本地电脑上创建startNgrok.sh脚本。内容是:
while [ -z $(iwconfig | grep "Link Quality") ]; do sleep 2 done ngrokc -SER[Shost:ngrok.你的域名,Sport:Day5中定义的http端口] -AddTun[Type:http,Lhost:127.0.0.1,Lport:8080,Sdname:自定义的次级域名] > /dev/null
首先通过while循环每隔2秒查询是否wifi模块已经成功进入STA模式。成功进入后再启动ngrokc。
-
本地电脑上创建lianjie.sh脚本。内容是:
iwlist wlan0 scanning > /tmp/wifiscan n_results=$(grep -c "ESSID:" /tmp/wifiscan) i=1 while [ "$i" -le "$n_results" ]; do if [ $i -lt 10 ]; then cell=$(echo "Cell 0$i - Address:") else cell=$(echo "Cell $i - Address:") fi j=`expr $i + 1` if [ $j -lt 10 ]; then nextcell=$(echo "Cell 0$j - Address:") else nextcell=$(echo "Cell $j - Address:") fi awk -v v1="$cell" -v v2="$nextcell" '$0 ~ v1 {p=1} $0 ~ v2{p=0}p' /tmp/wifiscan > /tmp/onecell mac=$(grep "Address:" /tmp/onecell | awk '{print $5}') ssid=$(grep "ESSID:" /tmp/onecell | awk '{sub(/^[ \s]+ESSID:/, ""); print}') encryption=$(grep "Encryption key:" /tmp/onecell | awk '{sub(/^[ \s]+Encryption key:/, "Encryption:"); print}') power=$(grep -o "Quality=[0-9]\{2\}" /tmp/onecell | awk '{sub(/Quality=/, ""); print}') power=`expr $power \* 10 / 7` power="Signal Strength= $power%" echo "$mac $ssid $encryption $power" >> /tmp/ssids i=`expr $i + 1` done rm -f /tmp/onecell awk '{printf("%3d : %s\n", NR, $0)}' /tmp/ssids > /tmp/sec_ssids echo "Available WIFI:" cat /tmp/sec_ssids echo "Please select a WIFI by entering its number, enter 0 or ctrl+c to quit" read nsel if [ $nsel = 0 ]; then rm /tmp/wifiscan rm /tmp/ssids rm /tmp/sec_ssids exit fi wifissid=$(grep " $nsel : " /tmp/sec_ssids | awk '{print $4}' | awk '{gsub(/"/, ""); print}' ) echo "You have choosen $wifissid" if [ $nsel -lt 10 ]; then cell=$(echo "Cell 0$nsel - Address:") else cell=$(echo "Cell $nsel - Address:") fi j=`expr $nsel + 1` if [ $j -lt 10 ]; then nextcell=$(echo "Cell 0$j - Address:") else nextcell=$(echo "Cell $j - Address:") fi awk -v v1="$cell" -v v2="$nextcell" '$0 ~ v1 {p=1} $0 ~ v2{p=0}p' /tmp/wifiscan > /tmp/cellinfo wifichannel=$(grep -o "Channel:[0-9]\{2\}" /tmp/cellinfo | awk '{sub(/Channel:/, ""); print}') wifimode=$(grep " WEP" /tmp/cellinfo) #check if encryption mode is WEP if [ -n "$wifimode" ]; then #check if $wifimode is not an empty string wifimode="wep" else wifimode=$(grep "WPA2 " /tmp/cellinfo) #check if encryption mode is WPA2 if [ -n "$wifimode" ]; then wifimode="psk2" else wifimode=$(grep "WPA " /tmp/cellinfo) #check if encryption mode is WPA if [ -n "$wifimode" ]; then wifimode="psk" else wifimode="none" fi fi fi encryp_on=$(grep " Encryption key:on" /tmp/cellinfo) if [ "none" = "$wifimode" ]&&[ -n "$encryp_on" ]; then echo " " echo "Impossible to detect wifi security mode automatically." echo "Please specify the seurity mode of the network." echo " 1: WPA" echo " 2: WPA2" echo " 3: WEP" echo " 4: Undefined" echo -n "Enter the numeric option for your security mode: " read sel_mode case "$sel_mode" in 1) wifimode="psk" ;; 2) wifimode="psk2" ;; 3) wifimode="wep" ;; 4) wifimode="none" ;; esac fi if [ "$wifimode" != "none" ]; then #ask for passwork when needed echo -n "Enter password of the selected WIFI network: " read wifipass fi rm /tmp/wifiscan rm /tmp/cellinfo rm /tmp/ssids rm /tmp/sec_ssids cp /etc/config/wireless.ap+sta /etc/config/wireless uci set wireless.radio0.channel=$wifichannel uci set wireless.station.mode="sta" uci set wireless.station.ssid="$wifissid" uci set wireless.station.encryption=$wifimode uci set wireless.station.key=$wifipass uci commit wireless echo -n " Trying to connect to WIFI network. (Wait a few seconds and check status with: iwconfig ) " wifi down wifi
这个脚本可以帮助我们很好的学习awk,grep,uci命令以及一些linux脚本的基础。所以这里不对它做很细的解释,把它的研读作为今天的进阶内容。它的第一步是将iwlist的扫描结果存储,再整理出这次找到的所有ssid的基本信息在屏幕上显示给用户,然后让用户选择一个想要连接的或者直接输入0退出,之后根据用户的选择,将ssid,encryption和channel自动识别,接着让用户输入wifi密码,之后将这些信息全部用uci命令填入wireless,最后重启wifi。有一个细节是当encryption不能自动识别时,它提供了让用户选择具体的加密方式的功能。好啦,就罗嗦到这里,这是一个很好的学习脚本,请认真读吧!
-
上传脚本到wifi模块。假设我们用的是有线连接将电脑和wifi模块连接起来。用
scp 存放startNgrok.sh的本地目录/startNgrok.sh root@192.168.1.1:/usr/bin/
和scp 存放lianjie.sh的本地目录/lianjie.sh root@192.168.1.1:/usr/bin/
将它们存入wifi模块的/usr/bin/系统环境目录。 -
将startNgrok脚本放入开机自启动。类似Day4,开机自启动可以在/etc/rc.local中设置,所以ssh登录wifi模块后,
vim /etc/rc.local
,内容是:reboot_ap_sta_detect.sh > /dev/null startNgrok.sh > /dev/null exit 0
-
之后如果需要连接新的wifi热点时,请记得用lianjie.sh就可以咯!恭喜!到此为止,项目的框架就结束了。之后可以做的事情有很多哦,比如自己搭建一个网站更加系统的管理这个live video。还可以用OpenVC的库将得到的mjpg视频进行运动检测,人脸检测,识别等等,这些都是在服务器端完成的任务了。
进阶
研读lianjie.sh。另外将从Day1到Day7的所有内容再整理一遍哦,思路清晰的写下自己的笔记。恭喜!耐心的将这个很可能是自己第一个网络应用搭建完成。