<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>润物无声 &#187; 润物无声</title>
	<atom:link href="http://blog.zhourunsheng.com/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhourunsheng.com</link>
	<description>天空一朵雨做的云</description>
	<lastBuildDate>Sat, 08 May 2021 05:17:21 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.41</generator>
	<item>
		<title>手机安装账户同步服务</title>
		<link>http://blog.zhourunsheng.com/2014/07/%e6%89%8b%e6%9c%ba%e5%ae%89%e8%a3%85%e8%b4%a6%e6%88%b7%e5%90%8c%e6%ad%a5%e6%9c%8d%e5%8a%a1/</link>
		<comments>http://blog.zhourunsheng.com/2014/07/%e6%89%8b%e6%9c%ba%e5%ae%89%e8%a3%85%e8%b4%a6%e6%88%b7%e5%90%8c%e6%ad%a5%e6%9c%8d%e5%8a%a1/#comments</comments>
		<pubDate>Mon, 21 Jul 2014 01:14:14 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Sony]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1905</guid>
		<description><![CDATA[<p>【前提】 手机需要root过，不然没有权限拷贝apk到 /system/app 目录下面。 【步骤】 通过手机 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/07/%e6%89%8b%e6%9c%ba%e5%ae%89%e8%a3%85%e8%b4%a6%e6%88%b7%e5%90%8c%e6%ad%a5%e6%9c%8d%e5%8a%a1/">手机安装账户同步服务</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<h3>【前提】</h3>
<p>手机需要root过，不然没有权限拷贝apk到 /system/app 目录下面。</p>
<h3>【步骤】</h3>
<p>通过手机的【设置】--【关于手机】 查看当前系统的Android版本，例如我的手机是4.2.2。<br />
在 <a href="http://wiki.rootzwiki.com/Google_Apps">http://wiki.rootzwiki.com/Google_Apps</a> 中下载对应的服务包。<br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/07/recommended_package_android.png" alt="" width="434" height="314" /></p>
<p>里面包含了很多的服务(system\app)app，我们只需要安装服务框架，登录服务，日历同步，通讯录同步，邮件同步即可。</p>
<p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/07/install_apks.png" alt="" /><br />
拷贝到 \system\app 系统目录中。<br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/07/copyapks.png" alt="" /></p>
<p><b>【账户同步】</b><br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/07/google_sync.png" alt="" /></p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/07/%e6%89%8b%e6%9c%ba%e5%ae%89%e8%a3%85%e8%b4%a6%e6%88%b7%e5%90%8c%e6%ad%a5%e6%9c%8d%e5%8a%a1/">手机安装账户同步服务</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2014/07/%e6%89%8b%e6%9c%ba%e5%ae%89%e8%a3%85%e8%b4%a6%e6%88%b7%e5%90%8c%e6%ad%a5%e6%9c%8d%e5%8a%a1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 制作一键安装盘（四）</title>
		<link>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e5%9b%9b%ef%bc%89/</link>
		<comments>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e5%9b%9b%ef%bc%89/#comments</comments>
		<pubDate>Fri, 23 May 2014 02:13:15 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[ISO]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1896</guid>
		<description><![CDATA[<p>本文测试原生的Kubuntu系统，基于原生Ubuntu系统，安装KDE环境后制作安装盘请参照文章《 Ubunt [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e5%9b%9b%ef%bc%89/">Ubuntu 制作一键安装盘（四）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>本文测试原生的Kubuntu系统，基于原生Ubuntu系统，安装KDE环境后制作安装盘请参照文章《 <a style="color: #69aa35;" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%E5%88%B6%E4%BD%9C%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85%E7%9B%98%EF%BC%88%E4%B8%89%EF%BC%89/">Ubuntu 制作一键安装盘（三）</a>》。</p>
<p>版本：Kubuntu 12.04<br />
下载地址：<a href="http://www.kubuntu.org/getkubuntu/download-lts">http://www.kubuntu.org/getkubuntu/download-lts</a></p>
<p>【更新源(主要是下载速度的因素)】<br />
deb http://mirrors.163.com/ubuntu/ precise main restricted universe multiverse<br />
deb http://mirrors.163.com/ubuntu/ precise-security main restricted universe multiverse<br />
deb http://mirrors.163.com/ubuntu/ precise-updates main restricted universe multiverse<br />
deb http://mirrors.163.com/ubuntu/ precise-proposed main restricted universe multiverse<br />
deb http://mirrors.163.com/ubuntu/ precise-backports main restricted universe multiverse<br />
deb-src http://mirrors.163.com/ubuntu/ precise main restricted universe multiverse<br />
deb-src http://mirrors.163.com/ubuntu/ precise-security main restricted universe multiverse<br />
deb-src http://mirrors.163.com/ubuntu/ precise-updates main restricted universe multiverse<br />
deb-src http://mirrors.163.com/ubuntu/ precise-proposed main restricted universe multiverse<br />
deb-src http://mirrors.163.com/ubuntu/ precise-backports main restricted universe multiverse</p>
<p><span style="color: #3665ee;"># Remastersys Precise</span><br />
<span style="color: #3665ee;">deb http://www.remastersys.com/ubuntu precise main</span></p>
<p>【添加公钥】<br />
wget -O - http://www.remastersys.com/ubuntu/remastersys.gpg.key | sudo apt-key add -</p>
<p>【安装 remastersys】<br />
sudo apt-get update; sudo apt-get install remastersys</p>
<p>【测试文件 (careytest/test.test)】</p>
<ul>
<li>/home 目录，存放用户相关配置信息</li>
<li>/etc 目录，存放全局配置信息</li>
<li>/usr/bin/ 目录，存放安装文件</li>
<li>/usr/lib/ 目录，存放库文件</li>
<li>/var/spool/ 目录，存放运行相关文件</li>
</ul>
<p>【采用 backup 方式备份全盘资料】<br />
sudo remastersys backup</p>
<p>【ISO 镜像文件测试】</p>
<ul>
<li>live 模式测试，文件全部存在，内容一致</li>
<li>install 安装测试，文件全部都在，内容一致，</li>
</ul>
<blockquote><p><span style="color: #ff0000;">注：在安装过程中自己创建的用户被丢弃</span></p></blockquote>
<p>【ISC* 镜像文件测试】</p>
<ul>
<li><b><span style="color: #41ad1c;">测试通过</span></b></li>
</ul>
<p>【总结】</p>
<ul>
<li>如果是GNOME的主题，采用原生Ubuntu系统</li>
<li>如果是KDE的主题，采用原生KUbuntu系统</li>
</ul>
<p>【参考资料】</p>
<ul>
<li>Creating Custom Kubuntu Using Remastersys:<a href="http://www.youtube.com/watch?v=wAvZr5z6Y-Q">http://www.youtube.com/watch?v=wAvZr5z6Y-Q</a></li>
<li><a href="http://www.psychocats.net/ubuntu/remastersys">http://www.psychocats.net/ubuntu/remastersys</a></li>
<li>《 <a style="color: #69aa35;" href="https://app.yinxiang.com/shard/s1/nl/113357/1ddcc9aa-7154-4d99-ab46-ddfb036586cc">Remaster your system with Remastersys – tobrunet.ch Techblog</a>》</li>
<li>《 <a style="color: #69aa35;" href="https://app.yinxiang.com/shard/s1/nl/113357/39c45340-8a46-41ce-bbb8-52ed84d53775">Free Imaging software - CloneZilla &amp; PartImage - Tutorial</a>》</li>
</ul>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e5%9b%9b%ef%bc%89/">Ubuntu 制作一键安装盘（四）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e5%9b%9b%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ubuntu 制作一键安装盘（三）</title>
		<link>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%89%ef%bc%89/</link>
		<comments>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%89%ef%bc%89/#comments</comments>
		<pubDate>Fri, 23 May 2014 02:07:06 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[ISO]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1892</guid>
		<description><![CDATA[<p>Ubuntu gnome主题的安装光盘制作请参照文章《Ubuntu 制作一键安装盘（二）》，本文进行KDE桌面 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%89%ef%bc%89/">Ubuntu 制作一键安装盘（三）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>Ubuntu gnome主题的安装光盘制作请参照文章《<a style="color: #69aa35;" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%E5%88%B6%E4%BD%9C%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85%E7%9B%98%EF%BC%88%E4%BA%8C%EF%BC%89/">Ubuntu 制作一键安装盘（二）</a>》，本文进行KDE桌面环境的安装测试。</p>
<p><b><span style="color: #ff0000;">注意：经过测试 remastersys 不能很好的支持GNOME发行版安装的KDE的桌面环境。</span></b></p>
<p>【安装KDE桌面环境】</p>
<ol>
<li>sudo apt-get install kubuntu-desktop kde-standard</li>
<li>简体中文支持：sudo apt-get install language-pack-kde-zh-hans language-pack-kde-zh-hant</li>
</ol>
<p>【步骤】</p>
<ul>
<li>制作发布安装盘 sudo remastersys dist</li>
<li>live 模式测试, 版本 Ubuntu 12.04 KDE 32位</li>
</ul>
<blockquote><p>结果：进入KDE登录界面，因为custom账户没有密码，无法登录进去系统。</p></blockquote>
<ul>
<li>live 模式测试, 版本 Ubuntu 12.04 KDE 64位</li>
</ul>
<blockquote><p>结果：可以进入GNOME主题系统，但是因为缺少/var/spool/isc* 工作目录，后台测试程序不完整。</p></blockquote>
<p>考虑解决方案(isc* 为测试程序，工作目录在/var/spool/isc*)：<br />
1. 修改 /usr/bin/remastersys 脚本文件，加入自己的处理，例如拷贝必要的文件<br />
<code><br />
log_msg "Copying iscxxx files"<br />
service iscxxx stop &amp;&gt; /dev/null<br />
cp -rf /var/spool/isc* $WORKDIR/dummysys/var/spool/ &amp;&gt; /dev/null<br />
</code></p>
<p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_update_pro.png" alt="" width="1233" height="204" /></p>
<p>2. sudo remastersys dist</p>
<blockquote><p><span style="color: #3665ee;">结果2：可以进入GNOME主题系统，前后台程序运行正常。</span></p></blockquote>
<ul>
<li>install 模式测试，无法进行系统的安装，没有安装过程，直接进入live模式</li>
</ul>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%89%ef%bc%89/">Ubuntu 制作一键安装盘（三）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%89%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ubuntu 制作一键安装盘（二）</title>
		<link>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%ba%8c%ef%bc%89/</link>
		<comments>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%ba%8c%ef%bc%89/#comments</comments>
		<pubDate>Thu, 22 May 2014 02:11:55 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[ISO]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1888</guid>
		<description><![CDATA[<p>本文采用 Remastersys 制作安装盘，使用relinux制作安装盘，请参照上一篇文章 《Ubuntu  [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%ba%8c%ef%bc%89/">Ubuntu 制作一键安装盘（二）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>本文采用 Remastersys 制作安装盘，使用relinux制作安装盘，请参照上一篇文章 《<a style="color: #69aa35;" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%E5%88%B6%E4%BD%9C%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85%E7%9B%98%EF%BC%88%E4%B8%80%EF%BC%89/">Ubuntu 制作一键安装盘（一）</a>》。<br />
<span id="more-1888"></span></p>
<p>【步骤】</p>
<ul>
<li>修改源 /etc/apt/sources.list ，加入</li>
</ul>
<p><code># Remastersys Precise<br />
deb http://www.remastersys.com/ubuntu precise main</code></p>
<ul>
<li>安装RemasterSys，sudo apt-get update; sudo apt-get install remastersys，</li>
</ul>
<p><code>如果出现GPG错误，请参照文章最后[错误解决]。<br />
错误解决的另一种方法, Add repository key:<br />
wget -O - http://www.remastersys.com/ubuntu/remastersys.gpg.key | sudo apt-key add -</code></p>
<ul>
<li>进行备份</li>
<li>
<ul>
<li>sudo remastersys dist cdfs</li>
</ul>
</li>
</ul>
<p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_distcdfs.png" alt="" width="1366" height="744" /></p>
<ul>
<li>
<ul>
<li>sudo remastersys dist iso custom.iso，生成 iso文件，大约 1.2GB</li>
</ul>
</li>
</ul>
<p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_distiso.png" alt="" width="1366" height="744" /></p>
<ul>
<li>
<ul>
<li>拷贝出来 sudo cp /home/remastersys/remastersys/custom.iso /media/sf_vmshare/</li>
</ul>
</li>
<li>新建虚拟机进行测试，运行 live 模式，guest账户登录，测试程序可以正常运行，测试通过</li>
</ul>
<p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_ubuntu_live.png" alt="" /></p>
<ul>
<li>系统安装测试，测试通过</li>
</ul>
<p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_ubuntu_install.png" alt="" /><br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_ubuntu_run.png" alt="" /></p>
<ul>
<li>可选："sudo remastersys dist" 方式 live 光盘测试,测试通过</li>
</ul>
<p><b><span style="color: #ff0000;">注：</span></b><br />
<b><span style="color: #ff0000;">更简便的方法可以采用 sudo remastersys backup，它可以同时备份用户账号信息。</span></b><br />
<b><span style="color: #ff0000;">采用 sudo remastersys dist，上面两步的合集。</span></b></p>
<p>【使用帮助】<br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_help.png" alt="" /></p>
<p>【参考资料】</p>
<ul>
<li>官网：<a href="http://www.remastersys.com/">http://www.remastersys.com/</a></li>
<li>百科Remastersys: <a href="http://baike.baidu.com/view/3051607.htm">http://baike.baidu.com/view/3051607.htm</a></li>
<li><a href="http://wiki.ubuntu.org.cn/Remastersys">http://wiki.ubuntu.org.cn/Remastersys</a></li>
</ul>
<p>【错误解决】</p>
<p>在安装更新时，运行命令行sudo apt-get update 或者运行更新管理器的时候，出现:</p>
<p>W: GPG 错误：http://ppa.launchpad.net precise Release: 由于没有公钥，无法验证下列签名： NO_PUBKEY <span style="text-decoration: underline;"><span style="color: #7600d8;">EAA903E3A2F4C039</span></span>错误，</p>
<p>解决方法：</p>
<p>在终端中运行：sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys <span style="text-decoration: underline;"><span style="color: #7600d8;">EAA903E3A2F4C039</span></span> 即可。</p>
<p>示例：<br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/remastersys_no_pubkey_error.png" alt="" width="1350" height="245" /></p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%ba%8c%ef%bc%89/">Ubuntu 制作一键安装盘（二）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%ba%8c%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ubuntu 制作一键安装盘（一）</title>
		<link>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%80%ef%bc%89/</link>
		<comments>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%80%ef%bc%89/#comments</comments>
		<pubDate>Thu, 22 May 2014 01:50:19 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[ISO]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1884</guid>
		<description><![CDATA[<p>基于 Ubuntu系统开发了一套系统，为了方便装机的便利性，制作一键安装盘。 注意：利用如下方法可以正常做出安 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%80%ef%bc%89/">Ubuntu 制作一键安装盘（一）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>基于 Ubuntu系统开发了一套系统，为了方便装机的便利性，制作一键安装盘。</p>
<p><span style="color: #ff0000;"><b>注意：利用如下方法可以正常做出安装盘，但是安装过程中会出现错误，另外运行live cd的时候也会出现如下low graphic的问题，暂时无解，第一次尝试失败。</b></span><br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/system_running_lowgf.png" alt="" /><br />
<span id="more-1884"></span></p>
<p>【步骤】</p>
<ul>
<li>下载软件 relinux，<a href="https://launchpad.net/relinux">https://launchpad.net/relinux</a>，例如 relinux_0.4a1-5_i386.deb</li>
<li>安装 sudo dpkg -i relinux_0.4a1-5_i386.deb</li>
<li>依赖错误修复 sudo apt-get install -f</li>
<li>语言环境（简体中文）设定 echo $LANG; export LANG='zh_CN.UTF-8'; echo $LANG</li>
<li>制作镜像 sudo relinux, 暂时保留默认设定</li>
</ul>
<p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/relinux_welcome.png" alt="" /><br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/relinux_configuration.png" alt="" /><br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/relinux_osweaver.png" alt="" /><br />
<img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/relinux_end.png" alt="" /></p>
<ul>
<li>查看 iso 文件，大小 2.0GB</li>
</ul>
<p><code>zhours@zhours-VirtualBox:~/relinux$ ll /home/relinux/<br />
总用量 1923372<br />
drwxr-xr-x  4 root root       4096  5月 12 15:09 ./<br />
drwxr-xr-x  4 root root       4096  5月 12 14:31 ../<br />
-rw-r--r--  1 root root 1969508352  5月 12 15:09 custom.iso<br />
-rw-r--r--  1 root root         47  5月 12 15:11 custom.iso.md5<br />
drwxr-xr-x  6 root root       4096  5月 12 15:05 .ISO_STRUCTURE/<br />
drwxr-xr-x 12 root root       4096  5月 12 14:31 .TMPSYS/<br />
zhours@zhours-VirtualBox:~/relinux$</code><br />
【参考资料】</p>
<ul>
<li>官方：<a href="https://launchpad.net/relinux">https://launchpad.net/relinux</a></li>
<li>视频：<a href="http://www.youtube.com/watch?v=3q6mibDs4Fo">http://www.youtube.com/watch?v=3q6mibDs4Fo</a></li>
<li>制作发布包《 <a style="color: #69aa35;" href="https://app.yinxiang.com/shard/s1/nl/113357/db2011d1-36ab-4135-bfe9-fabbf9bdafe5">Creating Your Own Distributable Ubuntu DVD (Relinux) | HowtoForge - Linux Howtos and Tutorials</a>》</li>
</ul>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%80%ef%bc%89/">Ubuntu 制作一键安装盘（一）</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2014/05/ubuntu-%e5%88%b6%e4%bd%9c%e4%b8%80%e9%94%ae%e5%ae%89%e8%a3%85%e7%9b%98%ef%bc%88%e4%b8%80%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>迁移博客图片资源从SAE到七牛</title>
		<link>http://blog.zhourunsheng.com/2014/05/%e8%bf%81%e7%a7%bb%e5%8d%9a%e5%ae%a2%e5%9b%be%e7%89%87%e8%b5%84%e6%ba%90%e4%bb%8esae%e5%88%b0%e4%b8%83%e7%89%9b/</link>
		<comments>http://blog.zhourunsheng.com/2014/05/%e8%bf%81%e7%a7%bb%e5%8d%9a%e5%ae%a2%e5%9b%be%e7%89%87%e8%b5%84%e6%ba%90%e4%bb%8esae%e5%88%b0%e4%b8%83%e7%89%9b/#comments</comments>
		<pubDate>Wed, 21 May 2014 01:57:02 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[Web设计]]></category>
		<category><![CDATA[SAE]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[七牛]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1880</guid>
		<description><![CDATA[<p>博客的很多图片资料存放在 SAE 上面，鉴于七牛的静态资源存储不错，计划迁移到七牛云存储上面，进而方便统一管理 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/%e8%bf%81%e7%a7%bb%e5%8d%9a%e5%ae%a2%e5%9b%be%e7%89%87%e8%b5%84%e6%ba%90%e4%bb%8esae%e5%88%b0%e4%b8%83%e7%89%9b/">迁移博客图片资源从SAE到七牛</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>博客的很多图片资料存放在 SAE 上面，鉴于七牛的静态资源存储不错，计划迁移到七牛云存储上面，进而方便统一管理。<br />
【下载 SAE Storage 中的资料】</p>
<ul>
<li>所需工具：Cyberduck</li>
<li>配置</li>
</ul>
<blockquote><p>服务器： auth.sinas3.com<br />
端口：443<br />
用户名：应用AccessKey<br />
密码：应用SecretKey</p></blockquote>
<blockquote><p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/cyberduck.png" alt="" /></p></blockquote>
<p><span id="more-1880"></span><br />
【上传到七牛】</p>
<ul>
<li>所需工具：qiniu-devtools-windows_386 [qrsync.exe]</li>
<li>配置, 新建 conf.json 文件</li>
</ul>
<blockquote><p>access_key： 应用AccessKey<br />
secret_key：应用SecretKey<br />
bucket：bucket 名称<br />
sync_dir：本地同步文件夹</p></blockquote>
<blockquote><p><img src="http://blog.zhourunsheng.com/wp-content/uploads/2014/05/confjson.png" alt="" /></p></blockquote>
<ul>
<li>执行 qrsync.exe conf.json 即可</li>
</ul>
<p>【外链切换】</p>
<ul>
<li>原外链地址：</li>
</ul>
<blockquote><p><span style="color: #ff0000;">http://carey-wordpress.stor.sinaapp.com</span>/uploads/2011/06/The-Moon-150x150.jpg</p></blockquote>
<ul>
<li>新外链地址：</li>
</ul>
<blockquote><p><span style="color: #ff0000;">http://carey.u.qiniudn.com</span>/uploads/2011/06/The-Moon-150x150.jpg</p></blockquote>
<p>【数据库相关】<br />
1. 查询包含外链的相关文章<br />
SELECT * FROM  `wp_posts` WHERE post_content LIKE  '%http://carey-wordpress.stor.sinaapp.com/%'</p>
<p>2. 指定文章替换<br />
UPDATE wp_posts SET post_content = replace(post_content, 'http://carey-wordpress.stor.sinaapp.com/', 'http://carey.u.qiniudn.com/') WHERE ID=24</p>
<p>3. 全局替换<br />
UPDATE wp_posts SET post_content = replace(post_content, 'http://carey-wordpress.stor.sinaapp.com/', 'http://carey.u.qiniudn.com/')</p>
<p>【资料相关】</p>
<ul>
<li>SAE 地址：<a href="http://sae.sina.com.cn/">http://sae.sina.com.cn/</a></li>
<li>SAE SVN 地址：<a href="https://svn.sinaapp.com/carey">https://svn.sinaapp.com/carey</a></li>
<li>七牛官方：<a href="https://portal.qiniu.com/">https://portal.qiniu.com/</a></li>
</ul>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2014/05/%e8%bf%81%e7%a7%bb%e5%8d%9a%e5%ae%a2%e5%9b%be%e7%89%87%e8%b5%84%e6%ba%90%e4%bb%8esae%e5%88%b0%e4%b8%83%e7%89%9b/">迁移博客图片资源从SAE到七牛</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2014/05/%e8%bf%81%e7%a7%bb%e5%8d%9a%e5%ae%a2%e5%9b%be%e7%89%87%e8%b5%84%e6%ba%90%e4%bb%8esae%e5%88%b0%e4%b8%83%e7%89%9b/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>搭建基于Flask框架的树莓派服务器</title>
		<link>http://blog.zhourunsheng.com/2013/11/%e6%90%ad%e5%bb%ba%e5%9f%ba%e4%ba%8eflask%e6%a1%86%e6%9e%b6%e7%9a%84%e6%a0%91%e8%8e%93%e6%b4%be%e6%9c%8d%e5%8a%a1%e5%99%a8/</link>
		<comments>http://blog.zhourunsheng.com/2013/11/%e6%90%ad%e5%bb%ba%e5%9f%ba%e4%ba%8eflask%e6%a1%86%e6%9e%b6%e7%9a%84%e6%a0%91%e8%8e%93%e6%b4%be%e6%9c%8d%e5%8a%a1%e5%99%a8/#comments</comments>
		<pubDate>Sat, 09 Nov 2013 02:15:57 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[移动开发]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[树莓派]]></category>
		<category><![CDATA[物联网]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1868</guid>
		<description><![CDATA[<p>本文展示了怎么样来利用Flask框架来搭建树莓派的服务器，然后通过web方式来控制物理硬件的开关~。背后的实现 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/11/%e6%90%ad%e5%bb%ba%e5%9f%ba%e4%ba%8eflask%e6%a1%86%e6%9e%b6%e7%9a%84%e6%a0%91%e8%8e%93%e6%b4%be%e6%9c%8d%e5%8a%a1%e5%99%a8/">搭建基于Flask框架的树莓派服务器</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>本文展示了怎么样来利用Flask框架来搭建树莓派的服务器，然后通过web方式来控制物理硬件的开关~。背后的实现原理是，在树莓派的平台上利用python语言开发包，开发IO通信程序，然后通过Flask框架，以web的方式展现出来，那么，这样就可以通过pc的web浏览器或者手持设备的web浏览器来控制实际的硬件开发，实现了物联网的远程控制。<span id="more-1868"></span></p>
<p>The following is an adapted excerpt from <a href="http://www.amazon.com/Getting-Started-Raspberry-Matt-Richardson/dp/1449344216/?tag=mattricha-20">Getting Started with Raspberry Pi</a>. I especially like this section of the book because it shows off one of the strengths of the Pi: its ability to combine modern web frameworks with hardware and electronics.</p>
<p>Not only can you use the Raspberry Pi to get data from servers via the internet, but your Pi can also act as a server itself. There are many different web servers that you can install on the Raspberry Pi. Traditional web servers, like Apache or lighttpd, serve the files from your board to clients. Most of the time, servers like these are sending HTML files and images to make web pages, but they can also serve sound, video, executable programs, and much more.</p>
<p>However, there's a new breed of tools that extend programming languages like Python, Ruby, and JavaScript to create web servers that dynamically generate the HTML when they receive HTTP requests from a web browser. This is a great way to trigger physical events, store data, or check the value of a sensor remotely via a web browser. You can even create your own JSON API for an electronics project!</p>
<h2>Flask Basics</h2>
<p>We're going to use a Python web framework called <a href="http://flask.pocoo.org/">Flask</a> to turn the Raspberry Pi into a dynamic web server. While there's a lot you can do with Flask "out of the box," it also supports many different extensions for doing things such as user authentication, generating forms, and using databases. You also have access to the wide variety of standard Python libraries that are available to you.</p>
<p>In order to install Flask, you'll need to have pip installed. If you haven't already installed pip, it's easy to do:</p>
<pre>pi@raspberrypi ~ $ sudo apt-get install python-pip</pre>
<p>After pip is installed, you can use it to install Flask and its dependencies:</p>
<pre>pi@raspberrypi ~ $ sudo pip install flask</pre>
<p>To test the installation, create a new file called <strong>hello-flask.py</strong> with the code from below.</p>
<h3>hello-flask.py</h3>
<pre>from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80, debug=True)</pre>
<p>Here's a breakdown of each line of code:</p>
<pre>from flask import Flask</pre>
<p>Load the Flask module into your Python script</p>
<pre>app = Flask(__name__)</pre>
<p>Create a Flask object called app</p>
<pre>@app.route("/")
    def hello():</pre>
<p>Run the code below this function when someone accesses the root URL of the server</p>
<pre>return "Hello World!"</pre>
<p>Send the text "Hello World!" to the client's web browser</p>
<pre>if __name__ == "__main__":</pre>
<p>If this script was run directly from the command line</p>
<pre>app.run(host='0.0.0.0', port=80, debug=True)</pre>
<p>Have the server listen on port 80 and report any errors.</p>
<p>NOTE: Before you run the script, you need to know your Raspberry Pi's IP address. You can run <strong>ifconfig</strong> to find it. An alternative is to install avahi-daemon (run <strong>sudo apt-get install avahi-daemon</strong> from the command line). This lets you access the Pi on your local network through the address http://raspberrypi.local. If you're accessing the Raspberry Pi web server from a Windows machine, you may need to put <a href="http://support.apple.com/kb/DL999">Bonjour Services</a> on it for this to work.</p>
<p>Now you're ready to run the server, which you'll have to do as root:</p>
<pre>pi@raspberrypi ~ $ sudo python hello-flask.py
 * Running on http://0.0.0.0:80/
 * Restarting with reloader</pre>
<p>From another computer on the same network as the Raspberry Pi, type your Raspberry Pi's IP address into a web browser. If your browser displays "Hello World!", you know you've got it configured correctly. You may also notice that a few lines appear in the terminal of the Raspberry Pi:</p>
<pre>10.0.1.100 - - [19/Nov/2012 00:31:31] "GET / HTTP/1.1" 200 -
10.0.1.100 - - [19/Nov/2012 00:31:31] "GET /favicon.ico HTTP/1.1" 404 -</pre>
<p>The first line shows that the web browser requested the root URL and our server returned HTTP status code 200 for "OK." The second line is a request that many web browsers send automatically to get a small icon called a <em>favicon</em> to display next to the URL in the browser's address bar. Our server doesn't have a <strong>favicon.ico</strong> file, so it returned HTTP status code 404 to indicate that the URL was not found.</p>
<h2>Templates</h2>
<p>If you want to send the browser a site formatted in proper HTML, it doesn't make a lot of sense to put all the HTML into your Python script. Flask uses a template engine called <a href="http://jinja.pocoo.org/docs/templates/">Jinja2</a> so that you can use separate HTML files with placeholders for spots where you want dynamic data to be inserted.</p>
<p>If you've still got <strong>hello-flask.py</strong> running, press Control-C to kill it.</p>
<p>To make a template, create a new file called <strong>hello-template.py</strong> with the code from below. In the same directory with <strong>hello-template.py</strong>, create a subdirectory called <strong>templates</strong>. In the<strong>templates</strong> subdirectory, create a file called <strong>main.html</strong> and insert the code from below. Anything in double curly braces within the HTML template is interpreted as a variable that would be passed to it from the Python script via the <strong>render_template</strong> function.</p>
<h3>hello-template.py</h3>
<pre>from flask import Flask, render_template
import datetime
app = Flask(__name__)

@app.route("/")
def hello():
   now = datetime.datetime.now()
   timeString = now.strftime("%Y-%m-%d %H:%M")
   templateData = {
      'title' : 'HELLO!',
      'time': timeString
      }
   return render_template('main.html', **templateData)

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)</pre>
<p>Let's take a look at some of the important lines of code.</p>
<pre>now = datetime.datetime.now()</pre>
<p>Get the current time and store it in the object <strong>now</strong></p>
<pre>timeString = now.strftime("%Y-%m-%d %H:%M")</pre>
<p>Create a formatted string using the date and time from the <strong>now</strong> object</p>
<pre>templateData = {
   'title' : 'HELLO!',
   'time': timeString
   }</pre>
<p>Create a <em>dictionary</em> of variables (a set of <em>keys</em>, such as <strong>title</strong> that are associated with values, such as <strong>HELLO!</strong>) to pass into the template</p>
<pre>return render_template('main.html', **templateData)</pre>
<p>Return the <strong>main.html</strong> template to the web browser using the variables in the <strong>templateData</strong>dictionary</p>
<h3>main.html</h3>
<pre>&lt;!DOCTYPE html&gt;
   &lt;head&gt;
      &lt;title&gt;{{ title }}&lt;/title&gt;
   &lt;/head&gt;

   &lt;body&gt;
      &lt;h1&gt;Hello, World!&lt;/h1&gt;
      &lt;h2&gt;The date and time on the server is: {{ time }}&lt;/h2&gt;
   &lt;/body&gt;
&lt;/html&gt;</pre>
<p>In <strong>main.html</strong>, any time you see a word within double curly braces, it'll be replaced with the matching key's value from the <strong>templateData</strong> dictionary in <strong>hello-template.py</strong>.</p>
<p>Now, when you run <strong>hello-template.py</strong> (as before, you need to use <strong>sudo</strong> to run it) and pull up your Raspberry Pi's address in your web browser, you should see a formatted HTML page with the title "HELLO!" and the Raspberry Pi's current date and time.</p>
<p>NOTE: While it's dependent on how your network is set up, it's unlikely that this page is accessible from outside your local network via the Internet. If you'd like to make the page available from outside your local network, you'll need to configure your router for port forwarding. Refer to your router's documentation for more information about how to do this.</p>
<h2>Connecting the Web to the Real World</h2>
<p>You can use Flask with other Python libraries to bring additional functionality to your site. For example, with the <a href="https://pypi.python.org/pypi/RPi.GPIO">RPi.GPIO</a> Python module you can create a website that interfaces with the physical world. To try it out, hook up a three buttons or switches to pins 23, 24, and 25 as shown in this graphic:</p>
<p><img alt="Connecting three buttons to Raspberry Pi" src="http://mattrichardson.com/images/Raspi-Buttons.png" /></p>
<p>The following code expands the functionality of <strong>hello-template.py</strong>, so copy it to a new file called <strong>hello-gpio.py</strong>. Add the RPi.GPIO module and a new <em>route</em> for reading the buttons, as I've done in the code below. The new route will take a variable from the requested URL and use that to determine which pin to read.</p>
<h3>hello-gpio.py</h3>
<pre>from flask import Flask, render_template
import datetime
import RPi.GPIO as GPIO
app = Flask(__name__)

GPIO.setmode(GPIO.BCM)

@app.route("/")
def hello():
   now = datetime.datetime.now()
   timeString = now.strftime("%Y-%m-%d %H:%M")
   templateData = {
      'title' : 'HELLO!',
      'time': timeString
      }
   return render_template('main.html', **templateData)

@app.route("/readPin/&lt;pin&gt;")
def readPin(pin):
   try:
      GPIO.setup(int(pin), GPIO.IN)
      if GPIO.input(int(pin)) == True:
         response = "Pin number " + pin + " is high!"
      else:
         response = "Pin number " + pin + " is low!"
   except:
      response = "There was an error reading pin " + pin + "."

   templateData = {
      'title' : 'Status of Pin' + pin,
      'response' : response
      }

   return render_template('pin.html', **templateData)

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)</pre>
<p>Here are the highlights:</p>
<pre>@app.route("/readPin/&lt;pin&gt;")</pre>
<p>Add a dynamic route with pin number as a variable.</p>
<pre>   try:
      GPIO.setup(int(pin), GPIO.IN)
      if GPIO.input(int(pin)) == True:
         response = "Pin number " + pin + " is high!"
      else:
         response = "Pin number " + pin + " is low!"
   except:
      response = "There was an error reading pin " + pin + "."</pre>
<p>If the code indented below <strong>try</strong> raises an exception (that is, there's an error), run the code in the <strong>except</strong> block.</p>
<pre>GPIO.setup(int(pin), GPIO.IN)</pre>
<p>Take the pin number from the URL, convert it into an integer and set it as an input</p>
<pre>if GPIO.input(int(pin)) == True:
    response = "Pin number " + pin + " is high!"</pre>
<p>If the pin is high, set the response text to say that it's high</p>
<pre>else:
    response = "Pin number " + pin + " is low!"</pre>
<p>Otherwise, set the response text to say that it's low</p>
<pre>except:
    response = "There was an error reading pin " + pin + "."</pre>
<p>If there was an error reading the pin, set the response to indicate that</p>
<p>You'll also need to create a new template called <strong>pin.html</strong>. It's not very different from <strong>main.html</strong>, so you may want to copy <strong>main.html</strong> to <strong>pin.html</strong> and make the appropriate changes as shown</p>
<h3>pin.html</h3>
<pre>&lt;!DOCTYPE html&gt;
   &lt;head&gt;
      &lt;title&gt;{{ title }}&lt;/title&gt;
   &lt;/head&gt;

   &lt;body&gt;
      &lt;h1&gt;Pin Status&lt;/h1&gt;
      &lt;h2&gt;{{ response }}&lt;/h2&gt;
   &lt;/body&gt;
&lt;/html&gt;</pre>
<p>With <strong>hello-gpio.py</strong> running, when you point your web browser to your Raspberry Pi's IP address, you should see the standard "Hello World!" page we created before. But add<strong>/readPin/24</strong> to the end of the URL, so that it looks something like<strong>http://10.0.1.103/readPin/24</strong>. A page should display showing that the pin is being read as low. Now hold down the button connected to pin 24 and refresh the page; it should now show up as high!</p>
<p>Try the other buttons as well by changing the URL. The great part about this code is that we only had to write the function to read the pin once and create the HTML page once, but it's almost as though there are separate webpages for each of the pins!</p>
<h2>Project: WebLamp</h2>
<p>In chapter 7 of <a href="http://www.amazon.com/Getting-Started-Raspberry-Matt-Richardson/dp/1449344216/?tag=mattricha-20">Getting Started with Raspberry Pi</a>, Shawn and I show you how to use Raspberry Pi as a simple AC outlet timer using the Linux job scheduler, <strong>cron</strong>. Now that you know how to use Python and Flask, you can now control the state of a lamp over the web. This basic project is simply a starting point for creating Internet-connected devices with the Raspberry Pi.</p>
<p>And just like how the previous Flask example showed how you can have the same code work on multiple pins, you'll set up this project so that if you want to control more devices in the future, it's easy to add.</p>
<p>Connect a Power Switch Tail II to pin 25 of the Raspberry Pi, as shown in the illustration below. If you don't have a Power Switch Tail, you can connect an LED to the pin to try this out for now.</p>
<p><img alt="Conencting Power Switch Tail to Raspberry Pi" src="http://mattrichardson.com/images/raspi-power-tail.jpg" /></p>
<p>If you have another PowerSwitch Tail II relay, connect it to pin 24 to control a second AC device. Otherwise, just connect an LED to pin 24. We're simply using it to demonstrate how multiple devices can be controlled with the same code.</p>
<p>Create a new directory in your home directory called <strong>WebLamp</strong>.</p>
<p>In <strong>WebLamp</strong>, create a file called <strong>weblamp.py</strong> and put in the code from below:</p>
<h3>weblamp.py</h3>
<pre>import RPi.GPIO as GPIO
from flask import Flask, render_template, request
app = Flask(__name__)

GPIO.setmode(GPIO.BCM)

# Create a dictionary called pins to store the pin number, name, and pin state:
pins = {
   24 : {'name' : 'coffee maker', 'state' : GPIO.LOW},
   25 : {'name' : 'lamp', 'state' : GPIO.LOW}
   }

# Set each pin as an output and make it low:
for pin in pins:
   GPIO.setup(pin, GPIO.OUT)
   GPIO.output(pin, GPIO.LOW)

@app.route("/")
def main():
   # For each pin, read the pin state and store it in the pins dictionary:
   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin)
   # Put the pin dictionary into the template data dictionary:
   templateData = {
      'pins' : pins
      }
   # Pass the template data into the template main.html and return it to the user
   return render_template('main.html', **templateData)

# The function below is executed when someone requests a URL with the pin number and action in it:
@app.route("/&lt;changePin&gt;/&lt;action&gt;")
def action(changePin, action):
   # Convert the pin from the URL into an integer:
   changePin = int(changePin)
   # Get the device name for the pin being changed:
   deviceName = pins[changePin]['name']
   # If the action part of the URL is "on," execute the code indented below:
   if action == "on":
      # Set the pin high:
      GPIO.output(changePin, GPIO.HIGH)
      # Save the status message to be passed into the template:
      message = "Turned " + deviceName + " on."
   if action == "off":
      GPIO.output(changePin, GPIO.LOW)
      message = "Turned " + deviceName + " off."
   if action == "toggle":
      # Read the pin and set it to whatever it isn't (that is, toggle it):
      GPIO.output(changePin, not GPIO.input(changePin))
      message = "Toggled " + deviceName + "."

   # For each pin, read the pin state and store it in the pins dictionary:
   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin)

   # Along with the pin dictionary, put the message into the template data dictionary:
   templateData = {
      'message' : message,
      'pins' : pins
   }

   return render_template('main.html', **templateData)

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)</pre>
<p>Since there's a lot going on in this code, I've placed on the explanations inline, as comments.</p>
<p>Create a new directory within <strong>WebLamp</strong> called <strong>templates</strong>.</p>
<p>Inside <strong>templates</strong>, create the file <strong>main.html</strong>:</p>
<h3>main.html</h3>
<pre>&lt;!DOCTYPE html&gt;
&lt;head&gt;
   &lt;title&gt;Current Status&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
   &lt;h1&gt;Device Listing and Status&lt;/h1&gt;

   {% for pin in pins %}
   &lt;p&gt;The {{ pins[pin].name }}
   {% if pins[pin].state == true %}
      is currently on (&lt;a href="/{{pin}}/off"&gt;turn off&lt;/a&gt;)
   {% else %}
      is currently off (&lt;a href="/{{pin}}/on"&gt;turn on&lt;/a&gt;)
   {% endif %}
   &lt;/p&gt;
   {% endfor %}

   {% if message %}
   &lt;h2&gt;{{ message }}&lt;/h2&gt;
   {% endif %}

&lt;/body&gt;
&lt;/html&gt;</pre>
<p>There are two templating concepts being illustrated in this file. First:</p>
<pre>{% for pin in pins %}
&lt;p&gt;The {{ pins[pin].name }}
{% if pins[pin].state == true %}
   is currently on (&lt;a href="/{{pin}}/off"&gt;turn off&lt;/a&gt;)
{% else %}
   is currently off (&lt;a href="/{{pin}}/on"&gt;turn on&lt;/a&gt;)
{% endif %}
&lt;/p&gt;
{% endfor %}</pre>
<p>This sets up a for loop to cycle through each pin, print its name and its state. It then gives the option to change its state, based on its current state. Second:</p>
<pre>   {% if message %}
   &lt;h2&gt;{{ message }}&lt;/h2&gt;
   {% endif %}</pre>
<p>This if statement will print a message passed from your Python script if there's a message set (that is, a change happened).</p>
<p>In terminal, navigate to the <strong>WebLamp</strong> directory and start the server (be sure to use Control-C to kill any other Flask server you have running first):</p>
<pre>pi@raspberrypi ~/WebLamp $ sudo python weblamp.py</pre>
<p><img alt="The device interface, as viewed through a phone's web browser" src="http://mattrichardson.com/images/Flask-phone.png" /></p>
<p>The best part about writing the code in this way is that you can very easily add as many devices that the hardware will support. Simply add the information about the device to the pins dictionary. When you restart the server, the new device will appear in the status list and its control URLs will work automatically.</p>
<p>There's another great feature built in: if you want to be able to flip the switch on a device with a single tap on your phone, you can create a bookmark to the address<strong>http://ipaddress/pin/toggle</strong>. That URL will check the pin's current state and switch it.</p>
<p>For more information about using Raspberry Pi, check out <a href="http://www.amazon.com/Getting-Started-Raspberry-Matt-Richardson/dp/1449344216/?tag=mattricha-20">Getting Started with Raspberry Pi</a>.</p>
<p>文章节选：<a href="http://mattrichardson.com/Raspberry-Pi-Flask/" target="_blank">http://mattrichardson.com/Raspberry-Pi-Flask/</a></p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/11/%e6%90%ad%e5%bb%ba%e5%9f%ba%e4%ba%8eflask%e6%a1%86%e6%9e%b6%e7%9a%84%e6%a0%91%e8%8e%93%e6%b4%be%e6%9c%8d%e5%8a%a1%e5%99%a8/">搭建基于Flask框架的树莓派服务器</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2013/11/%e6%90%ad%e5%bb%ba%e5%9f%ba%e4%ba%8eflask%e6%a1%86%e6%9e%b6%e7%9a%84%e6%a0%91%e8%8e%93%e6%b4%be%e6%9c%8d%e5%8a%a1%e5%99%a8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android云推送之GCM</title>
		<link>http://blog.zhourunsheng.com/2013/09/android%e4%ba%91%e6%8e%a8%e9%80%81%e4%b9%8bgcm/</link>
		<comments>http://blog.zhourunsheng.com/2013/09/android%e4%ba%91%e6%8e%a8%e9%80%81%e4%b9%8bgcm/#comments</comments>
		<pubDate>Sat, 28 Sep 2013 01:39:37 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[移动开发]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[GCM]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1860</guid>
		<description><![CDATA[<p>本文展示了怎样来利用谷歌的云推送系统Google Cloud Messaging (GCM)来推送消息到And [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/09/android%e4%ba%91%e6%8e%a8%e9%80%81%e4%b9%8bgcm/">Android云推送之GCM</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>本文展示了怎样来利用谷歌的云推送系统Google Cloud Messaging (GCM)来推送消息到Android手机，目前支持两大类消息，一类是“send-to-sync”，即发送一个触发指令，格式为一个自定义的字符串，例如 "syncTime"表示同步时间，那么Android客户端收到此消息的话，需要启动一个后台线程，同设定的Server进行交互，获取最新的时间；还有一类是“message with payload”，即发送一条消息，消息中可包含正文内容，比如message.addData("new_time", curTime)，则可以通过键值"new_time"获取到具体的时间。<span id="more-1860"></span></p>
<p>Pushing data has a number of benefits such as increased battery life and decreased server load. GCM is free to use and has no quotas, so it is a perfect candidate to handle the heavy lifting required for data updates.</p>
<p>There are two types of messages you can push with GCM: Send-to-sync and message with payload. A send-to-sync is basically a tickle, telling your app to sync with the server while a message with payload lets you send data in the push message (up to 4kb). Here’s a simple, full stack example that will help highlight how to get each of these types of push messages integrated with your app.</p>
<p>The app will take either a push message with a payload that updates the time that is saved on the device or a send to sync message that triggers the app to sync the time with the server. This was created using the “Generate App Engine Backend” feature of Android Studio. The Android developers blog has a <a href="http://android-developers.blogspot.com/2013/06/adding-backend-to-your-app-in-android.html">tutorial</a> on this. If you already have a backend setup, the GCM setup instructions for an existing server can be found <a href="http://developer.android.com/google/gcm/server.html">here</a>.</p>
<p>The source for this example is up on <a href="https://github.com/doubleencore/PushDontPoll" target="_blank">GitHub</a>.</p>
<h2>Create a new endpoint</h2>
<p>Wizard generated files <em>Message.java</em> and <em>MessageEndpoint.java</em> in PushDontPoll-AppEngine were deleted, along with the <em>messageendpoint</em> package in PushDontPoll-endpoints. In lieu of this, <em>DateEndpoint.java</em> was created in PushDontPoll-AppEngine. This class makes an endpoint at <em>/_ah/api/dateendpoint/v1/currentdate</em> that provides the current time in JSON:</p>
<pre>    @JsonAutoDetect
    public static class CurrentDate {

        @JsonProperty
        private long date = new Date().getTime();

        public long getDate() {
            return date;
        }
    }

    @ApiMethod(name = "currentDate")
    public CurrentDate getDate() {
        return new CurrentDate();
    }</pre>
<p>It also provides methods to send a message with payload and send to sync message via GCM. This was ripped out the deleted <em>MessageEndpoint.java</em> , so it only sends messages to a maximum of 10 devices. They are both built using GCM’s <a href="http://developer.android.com/reference/com/google/android/gcm/server/Message.Builder.html">Message.Builder()</a>.</p>
<p>The message with payload adds the time to the data parameter. Key/value pairs added here will be automatically added as extras in the the intent bundle when parsing the message.</p>
<pre>    String newTime = String.valueOf(new Date().getTime());
    Message message = new Message.Builder()
            .addData("new_time", newTime)
            .build();</pre>
<p>The send-to-sync message uses a collapse key so that only one message will be delivered if multiple tickles are queued up. You should not use more than four distinct keys since that is the maximum number that the GCM server can store. You can read more about this parameter <a href="http://developer.android.com/google/gcm/adv.html#msg-lifetime">here</a>.</p>
<pre>    Message message = new Message.Builder()
            .collapseKey("syncTime")
            .build();</pre>
<h2>Add send-to-sync and payload message buttons</h2>
<p>The <em>index.html</em> in the PushDontPoll-AppEngine project was modified to add buttons that allow us to send the two different types of push messages. Most of the wizard-generated code was removed for simplicity. The code to show the buttons is:</p>
<pre>  &lt;div&gt;
      &lt;button id="sendTickleButton"&gt;Send Tickle&lt;/button&gt;
  &lt;/div&gt;

  &lt;div&gt;
      &lt;button id="sendUpdateButton"&gt;Send Update&lt;/button&gt;
  &lt;/div&gt;</pre>
<p>The functions that they call are:</p>
<pre>  &lt;script type="text/javascript"&gt;
    $("#sendTickleButton").click(sendTickle);
    $("#successArea").hide();
  &lt;/script&gt;
  &lt;script type="text/javascript"&gt;
    $("#sendUpdateButton").click(sendUpdate);
    $("#successArea").hide();
  &lt;/script&gt;

  function sendTickle() {
    gapi.client.dateendpoint
    .sendTickle()
    .execute(handleMessageResponse);
  }

  function sendUpdate() {
    gapi.client.dateendpoint
    .sendUpdate()
    .execute(handleMessageResponse);
  }</pre>
<p>These call the <em>sendTickle()</em> and <em>sendUpdate()</em> methods in <em>DateEndpoint.java</em>. Make sure you re-generate the client libraries after changing the PushDontPoll-AppEngine code (Tools -&gt; Google Cloud Endpoints -&gt; Generate Client Libraries).</p>
<h2>Add code to parse GCM message</h2>
<p>The wizard-generated files <em>RegisterActivity.java</em> and <em>GCMIntentService.java</em> were moved to the main project so they could use the <em>Constants</em> class. The added application code to show the saved time was added to the <em>MainActivity</em>class in order to keep things separated and easy to understand. The <em>RegisterActivity</em> is accessible via an action item.</p>
<p>Parsing the GCM message is done in the <em>onMessage()</em> method in the <em>GCMIntentService</em> class. This class is already fleshed out for you thanks to the wizard.</p>
<h2>Parse send-to-sync</h2>
<p>The send-to-sync message will have a <em>collapse_key</em>, so we can request a sync if that matches the sync type we’re expecting:</p>
<pre>    if ("syncTime".equals(intent.getStringExtra("collapse_key"))) {
        Account[] accounts = AccountManager.get(this).getAccountsByType(Constants.ACCOUNT_TYPE);
        if (accounts.length &gt; 0) {
            Bundle bundle = new Bundle(2);
            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
            ContentResolver.requestSync(accounts[0], Constants.AUTHORITY, bundle);
        }
        [snip]</pre>
<p>This uses a sync adapter with a stubbed authenticator and content provider – see <a href="http://developer.android.com/training/sync-adapters/index.html">here</a> for more info. This can easily be modified to send a network request to sync using your method of choice (Volley, Retrofit, etc) if a sync adapter is not desirable. All of the syncing code is in the <em>com.doubleencore.android.pushdontpoll.sync</em> package, along with the necessary xml files in <em>res/xml/</em> and in the <em>AndroidManifest.xml</em>.</p>
<p>In the <em>onPerformSync()</em> of the <em>SyncAdapter</em>, we can make a network request to the new endpoint that was created to get the current time:</p>
<pre>    Dateendpoint.Builder endpointBuilder = new Dateendpoint.Builder(
            AndroidHttp.newCompatibleTransport(),
            new JacksonFactory(),
            new HttpRequestInitializer() {
                @Override
                public void initialize(HttpRequest httpRequest) throws IOException {
                }
            });

    Dateendpoint endpoint = CloudEndpointUtils.updateBuilder(endpointBuilder).build();
    try {
        CurrentDate date = endpoint.currentDate().execute();
        long time = date.getDate();
        [snip]</pre>
<h2>Parse message with payload</h2>
<p>The message with payload will have <em>new_time</em> as a key in the intent extras. This key coincides with the one we added when building the message. You can read more about the data parameter <a href="http://developer.android.com/google/gcm/server.html#send-msg">here</a>.</p>
<pre>    if (intent.hasExtra("new_time")) {
        // Extract the data from the message
        long time = Long.parseLong(intent.getStringExtra("new_time"));
        [snip]</pre>
<p>In both cases, the time is then saved to shared preferences, and a local broadcast is sent to update the UI. Again, this can be done using your preferred method (event bus, observable cursor, etc).</p>
<pre>    SharedPreferences.Editor editor = getSharedPreferences(Constants.PREFS_NAME, 0).edit();
    editor.putLong(Constants.PREFS_KEY_TIME, time).apply();

    Intent updateIntent = new Intent(Constants.UPDATE_UI_INTENT_ACTION);
    LocalBroadcastManager.getInstance(this).sendBroadcast(updateIntent);</pre>
<h2>Running the server</h2>
<p>In order to use GCM, you must <a href="http://developer.android.com/google/gcm/gs.html">have an API key</a>. You can enter this when running the wizard or by replacing it in <em>DateEndpoint.java</em> in the PushDontPoll-AppEngine project. The server can either be deployed as an App Engine app or run locally using the dev server.</p>
<h2>Local instance</h2>
<p>To run it as a local instance, you need to change:</p>
<pre>    //PushDontPoll-endpoints Project - CloudEndpointUtils.java
    protected static final boolean LOCAL_ANDROID_RUN = true;</pre>
<p>Then you can just run the <em>appengine:devserver</em> maven goal, and it will be running on localhost. The server will now work with a Google API emulator.</p>
<p>If you want to access this local instance on a device (it must be on the same network as the local instance,) you’ll also need to change:</p>
<pre>    //PushDontPoll-endpoints Project - CloudEndpointUtils.java
    protected static final String LOCAL_APP_ENGINE_SERVER_URL_FOR_ANDROID = "http://[local_ip_address]:8080";</pre>
<p>…and download the App Engine SDK from <a href="https://developers.google.com/appengine/downloads">here</a>, and run:</p>
<pre>    appengine-java-sdk/bin/dev_appserver.sh --address 0.0.0.0 [project_directory]/PushDontPoll-Appegine/target/PushDontPoll-AppEngine-1.0</pre>
<h2>App Engine app</h2>
<p>If you didn’t follow along in the blog and are just trying to get the sample code running, you need to create a Google Cloud Platform project and obtain the Project Number and Project ID. You can do this by following the Preliminary Setup section of <a href="http://android-developers.blogspot.com/2013/06/adding-backend-to-your-app-in-android.html">this blog post</a>.</p>
<p>Set the <em>PROJECT_NUMBER</em> variable in <em>GCMIntentService.java</em> to your project number and the <em>&lt;application&gt;</em> tag in <em>appengine-web.xml</em> to your project ID, and regenerate the client libraries.</p>
<p>You may also want to change the packages (<em>com.doubleencore.android</em>) and domains (<em>doubleencore.com</em>) to your domain.</p>
<p>Deploy the backend server by running the <em>appengine:update</em> maven goal. You can then access your server at<em>http://&lt;project-id&gt;.appspot.com</em>.</p>
<h2>Running the Android app</h2>
<p>You can now deploy the PushDontPoll app to your device or emulator. Once deployed, click on the GCM Register action item to register your device with the server. Once the success message appears, press back and navigate to your server on your computer. Pressing the “Send Tickle” button will push a message that signals the device to sync with the server. The device will hit the date endpoint for the current time, and the time should refresh on the device. Pressing the “Send Update” button will push a message that has the new time in the payload data. This should instantly update the time shown on the device without needing to make an additional trip to the server.</p>
<p>Hopefully, this simple example app will assist you in getting a push framework up and running for your app. I highly recommend reading through the <a href="http://developer.android.com/google/gcm/index.html">GCM documentation</a> to get a thorough understanding, as there are many features not discussed in this article. You will need to handle things, such as request spikes with send-to-sync messages, more gracefully than this sample does as well. Good luck and happy pushing!</p>
<p>文章节选：<a href="http://www.doubleencore.com/2013/09/push-dont-poll-how-to-use-gcm-to-update-app-data/" target="_blank">http://www.doubleencore.com/2013/09/push-dont-poll-how-to-use-gcm-to-update-app-data/</a></p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/09/android%e4%ba%91%e6%8e%a8%e9%80%81%e4%b9%8bgcm/">Android云推送之GCM</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2013/09/android%e4%ba%91%e6%8e%a8%e9%80%81%e4%b9%8bgcm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>备忘：C与C++之间的互相调用</title>
		<link>http://blog.zhourunsheng.com/2013/09/%e5%a4%87%e5%bf%98%ef%bc%9ac%e4%b8%8ec%e4%b9%8b%e9%97%b4%e7%9a%84%e4%ba%92%e7%9b%b8%e8%b0%83%e7%94%a8/</link>
		<comments>http://blog.zhourunsheng.com/2013/09/%e5%a4%87%e5%bf%98%ef%bc%9ac%e4%b8%8ec%e4%b9%8b%e9%97%b4%e7%9a%84%e4%ba%92%e7%9b%b8%e8%b0%83%e7%94%a8/#comments</comments>
		<pubDate>Fri, 20 Sep 2013 06:03:12 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[程序设计]]></category>
		<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1853</guid>
		<description><![CDATA[<p>最新在做Ubuntu上面的C++开发，其中用到了部分C库，那么就涉及到C和C++之间的混合调用，C++调用C语 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/09/%e5%a4%87%e5%bf%98%ef%bc%9ac%e4%b8%8ec%e4%b9%8b%e9%97%b4%e7%9a%84%e4%ba%92%e7%9b%b8%e8%b0%83%e7%94%a8/">备忘：C与C++之间的互相调用</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>最新在做Ubuntu上面的C++开发，其中用到了部分C库，那么就涉及到C和C++之间的混合调用，C++调用C语言比较方便，反之则要稍作变通。</p>
<h2>1. C++ 调用 C 语言</h2>
<p>头文件包含：</p>
<pre>extern "C"
{
#include "iec61850_server.h"
#include "iso_server.h"
#include "acse.h"
#include "thread.h"
#include "model.h"
}</pre>
<p>函数调用：</p>
<pre>IedServer_observeDataAttribute(iedServer, (DataAttribute*)mmsi.dmm, observerCallback);</pre>
<p>回调函数observerCallback的声明和实现如下：</p>
<pre>extern "C"
{
  void observerCallback(DataAttribute* dataAttribute)
  {
    call_Lib_daObserverCallback(mod, dataAttribute);
  }
}</pre>
<h2>2. C 调用 C++ 语言</h2>
<p>在C语言的函数中是无法直接调用C++代码的，如果要调用，需要做一个wrapper，例如call_Lib_daObserverCallback，它的声明和实现如下：</p>
<pre>extern "C" void call_Lib_daObserverCallback(Lib* p, DataAttribute* dataAttribute) // wrapper function
{
   p-&gt;daObserverCallback(dataAttribute);
}</pre>
<p>daObserverCallback 才是我们C++代码的实现：</p>
<pre>void Lib::daObserverCallback(DataAttribute* dataAttribute)
{
  map&lt;string, MMSINFO&gt;::iterator it;
  // ...
}</pre>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/09/%e5%a4%87%e5%bf%98%ef%bc%9ac%e4%b8%8ec%e4%b9%8b%e9%97%b4%e7%9a%84%e4%ba%92%e7%9b%b8%e8%b0%83%e7%94%a8/">备忘：C与C++之间的互相调用</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2013/09/%e5%a4%87%e5%bf%98%ef%bc%9ac%e4%b8%8ec%e4%b9%8b%e9%97%b4%e7%9a%84%e4%ba%92%e7%9b%b8%e8%b0%83%e7%94%a8/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>体验物联网</title>
		<link>http://blog.zhourunsheng.com/2013/09/%e4%bd%93%e9%aa%8c%e7%89%a9%e8%81%94%e7%bd%91/</link>
		<comments>http://blog.zhourunsheng.com/2013/09/%e4%bd%93%e9%aa%8c%e7%89%a9%e8%81%94%e7%bd%91/#comments</comments>
		<pubDate>Mon, 16 Sep 2013 01:47:15 +0000</pubDate>
		<dc:creator><![CDATA[润物无声]]></dc:creator>
				<category><![CDATA[云计算]]></category>
		<category><![CDATA[OpenSCADA]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[Weixin]]></category>
		<category><![CDATA[物联网]]></category>

		<guid isPermaLink="false">http://blog.zhourunsheng.com/?p=1847</guid>
		<description><![CDATA[<p>上个星期初步接触了物联网，正好工作手头有这些基本的器件，可以打造一个最简单的物联网环境，体验一下。本文的目的是 [&#8230;]</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/09/%e4%bd%93%e9%aa%8c%e7%89%a9%e8%81%94%e7%bd%91/">体验物联网</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></description>
				<content:encoded><![CDATA[<p>上个星期初步接触了物联网，正好工作手头有这些基本的器件，可以打造一个最简单的物联网环境，体验一下。本文的目的是展示一个基于温湿度数据采集的报警系统，当温度或者湿度达到一定的临界值，自动打开报警器，并且微信通知系统管理员，系统管理员也可以通过微信查询当前环境的实时温湿度数据。</p>
<p>【系统整体架构】</p>
<p><img class="alignnone" alt="" src="http://farm8.staticflickr.com/7443/9766709544_5761c66bd3_o.png" width="542" height="442" /><br />
1. PC端本地通过OpenScada系统采集温湿度的数据<br />
2. PC端本地将采集到的温湿度数据定时上报到云端，供PAD查询<br />
3. PC端本地检测温湿度的阀值，启动或者关闭报警设备<br />
4. PC端本地检测到报警信息，及时给云端报告告警信息，云端通过微信系统推送到系统管理员账号上<br />
5. 系统管理员通道PAD微信系统，查询当前环境的数据<span id="more-1847"></span></p>
<p>【硬件环境】<br />
1. 工作PC，ubuntu系统，运行openscada数据采集系统<br />
2. PAD一台，手机也可以，模拟器也行，能跑微信就行<br />
3. USB-485 转接器，PC上没有485端口，需要转换成USB通信协议<br />
3. FT-02RL开关量输入输出模块(MODBUS-RTU协议)，软件控制继电器开关<br />
4. 温湿度传感器，基于485 modbus的数据传输协议</p>
<p>【硬件布线】<br />
1. 注意一下电源的正负极，不要接反了<br />
2. 注意485的A B数据端口，不要接反了<br />
3. 其他的没啥问题了</p>
<p><img class="alignnone" alt="" src="http://farm4.staticflickr.com/3771/9766710004_edcff96ea4_z.jpg" width="480" height="640" /></p>
<p><img class="alignnone" alt="" src="http://farm4.staticflickr.com/3674/9766812174_e66c67d61c_z.jpg" width="640" height="480" /><br />
【软件环境】<br />
1. 本地PC运行Ubuntu 12.04 OS<br />
2. 本地实现OpenScada数据采集系统，可以采集Modbus协议的数据，和基于Modbus协议控制外设<br />
3. 远端的PHP服务器，采用的我博客（http://blog.zhourunsheng.com）的后台，基于wordpress + 插件<br />
4. 微信公众号的接入，像我下面的微信号是专门为博客服务的</p>
<p>【演示数据查询】<br />
1. 加入公众微信号，查询关键字“zhou_runsheng”，或者扫描如下的二维码，添加</p>
<p><img class="alignnone" alt="" src="http://blog.zhourunsheng.com/wp-content/uploads/2013/04/qrcode_runsheng_blog.jpg" width="430" height="430" /><br />
2. 发送查询指令，例如“查询温湿度”，返回当前环境温湿度数据<br />
&lt;&lt;&lt; 查询温湿度<br />
&gt;&gt;&gt; 温湿度数据：<br />
温度：33.5 度<br />
湿度：88.7%<br />
露点：18.7 度</p>
<p>3. 其他的指令还没有加入，如果输入其他的查询信息，默认会按照该关键词来搜索相关的博文展示</p>
<p><img class="alignnone" alt="" src="http://farm3.staticflickr.com/2809/9766669722_bb9fb18613_z.jpg" width="640" height="480" /></p>
<p>【演示报警】<br />
1. 加热温湿度采集器（O(∩_∩)O，用火烤烤，甭烧毁仪器就行）<br />
2. 加湿温湿度采集器（最简单的办法，对着仪器哈口气，湿度立马上升到99.99%）<br />
3. 当温湿度达到管理员配置的临界阀值（比如温度超过33摄氏度），产生报警<br />
4. 报警产生，报警器响铃，微信推送通知系统管理员</p>
<p><img class="alignnone" alt="" src="http://farm3.staticflickr.com/2814/9766609931_e7046c61bb_z.jpg" width="640" height="480" /></p>
<p>5. 湿度报警, 继电器开关打开,左数第一个亮起来的红灯</p>
<p><img class="alignnone" alt="" src="http://farm3.staticflickr.com/2870/9766709664_e8c524555d_z.jpg" width="640" height="480" /></p>
<p>【未来】<br />
目前仅仅实现了简单的数据采集+报警应急处理，推广到其他地方，比如智能家居，智能农田灌溉，智能监控系统等等，O(∩_∩)O哈哈~，先想想怎么样打造一套智能的家居吧~~~，把家里联网的东西全控制了。</p>
<p><a rel="nofollow" href="http://blog.zhourunsheng.com/2013/09/%e4%bd%93%e9%aa%8c%e7%89%a9%e8%81%94%e7%bd%91/">体验物联网</a>，首发于<a rel="nofollow" href="http://blog.zhourunsheng.com">润物无声</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.zhourunsheng.com/2013/09/%e4%bd%93%e9%aa%8c%e7%89%a9%e8%81%94%e7%bd%91/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
