├── .nojekyll ├── designiot.jpg ├── images ├── pm.png ├── 88x31.png ├── arch.jpeg ├── edit.png ├── flow.png ├── gpio.png ├── hwcnt.png ├── lnmp.gif ├── lnmp.jpg ├── rpi.jpg ├── shell.png ├── star.png ├── uno.png ├── arduino.png ├── change.png ├── getjson.png ├── nostyle.png ├── origin.png ├── python.png ├── box-model.gif ├── dom_tree.jpg ├── gnu_linux.png ├── hardware.jpg ├── redfonts.png ├── temperture.png ├── webkitflow.png ├── linux_kernel.jpg ├── xml-vs-json.png ├── fullconnected.png └── raspberrypi_flow.png ├── .gitignore ├── src ├── end │ └── qa.md ├── 2.0.webservices.md ├── pre │ ├── 1.pre.md │ └── 2.intro.md ├── futrue │ └── 3.2.mqtt.md ├── 2.1.restful.md ├── 1.9.server.md ├── 3.1.iot-coap.md ├── 1.8.rpi.md ├── 4.0.easyiot.md ├── 1.6.arduino.md ├── 2.2.init_env.md ├── 1.1.anywhere-html.md ├── 5.0.android.md ├── 1.3.anywhere-css.md ├── 2.1.http.md ├── 1.4.anywhere-hjc.md ├── 1.7.python.md ├── 2.5.frontend.md ├── 1.2.anywhere-javascript.md ├── 2.3.create_laravel.md ├── 1.5.linux.md └── 3.1.coap.md ├── template ├── headpdf.html ├── head-chapter.html ├── head.html └── template.tex ├── help.md ├── Makefile ├── README.md ├── css └── vendor.css ├── Licence.txt └── end └── iot.md /.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /designiot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/designiot.jpg -------------------------------------------------------------------------------- /images/pm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/pm.png -------------------------------------------------------------------------------- /images/88x31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/88x31.png -------------------------------------------------------------------------------- /images/arch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/arch.jpeg -------------------------------------------------------------------------------- /images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/edit.png -------------------------------------------------------------------------------- /images/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/flow.png -------------------------------------------------------------------------------- /images/gpio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/gpio.png -------------------------------------------------------------------------------- /images/hwcnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/hwcnt.png -------------------------------------------------------------------------------- /images/lnmp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/lnmp.gif -------------------------------------------------------------------------------- /images/lnmp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/lnmp.jpg -------------------------------------------------------------------------------- /images/rpi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/rpi.jpg -------------------------------------------------------------------------------- /images/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/shell.png -------------------------------------------------------------------------------- /images/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/star.png -------------------------------------------------------------------------------- /images/uno.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/uno.png -------------------------------------------------------------------------------- /images/arduino.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/arduino.png -------------------------------------------------------------------------------- /images/change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/change.png -------------------------------------------------------------------------------- /images/getjson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/getjson.png -------------------------------------------------------------------------------- /images/nostyle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/nostyle.png -------------------------------------------------------------------------------- /images/origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/origin.png -------------------------------------------------------------------------------- /images/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/python.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | build/iot.pdf 3 | build/designiot.pdf 4 | Makefile.old 5 | build/pdf.html -------------------------------------------------------------------------------- /images/box-model.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/box-model.gif -------------------------------------------------------------------------------- /images/dom_tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/dom_tree.jpg -------------------------------------------------------------------------------- /images/gnu_linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/gnu_linux.png -------------------------------------------------------------------------------- /images/hardware.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/hardware.jpg -------------------------------------------------------------------------------- /images/redfonts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/redfonts.png -------------------------------------------------------------------------------- /images/temperture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/temperture.png -------------------------------------------------------------------------------- /images/webkitflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/webkitflow.png -------------------------------------------------------------------------------- /images/linux_kernel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/linux_kernel.jpg -------------------------------------------------------------------------------- /images/xml-vs-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/xml-vs-json.png -------------------------------------------------------------------------------- /images/fullconnected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/fullconnected.png -------------------------------------------------------------------------------- /images/raspberrypi_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/gh-pages/images/raspberrypi_flow.png -------------------------------------------------------------------------------- /src/end/qa.md: -------------------------------------------------------------------------------- 1 | 2 | #尾声 3 | 4 | ##路 5 | 6 | ##其他 7 | 8 | 意见及建议: [https://github.com/phodal/designiot/issues](https://github.com/phodal/designiot/issues) 9 | 10 | 邮箱: [h@phodal.com](h@phodal.com) 11 | -------------------------------------------------------------------------------- /template/headpdf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 一步步搭建物联网系统(教你设计物联网系统) 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /template/head-chapter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 一步步搭建物联网系统(教你设计物联网系统) 4 | 5 | 6 | 7 | 8 | 9 |

一步步搭建物联网系统(教你设计物联网系统)

10 | 11 | -------------------------------------------------------------------------------- /src/2.0.webservices.md: -------------------------------------------------------------------------------- 1 | #Web服务 2 | 3 | Web服务是一种服务导向架构的技术,通过标准的Web协议提供服务,目的是保证不同平台的应用服务可以互操作。 4 | 5 | 根据W3C的定义,Web服务(Web service)应当是一个软件系统,用以支持网络间不同机器的互动操作。网络服务通常是许多应用程序接口(API)所组成的,它们透过网络,例如国际互联网(Internet)的远程服务器端,执行客户所提交服务的请求。 6 | 7 | 尽管W3C的定义涵盖诸多相异且无法介分的系统,不过通常我们指有关于主从式架构(Client-server)之间根据SOAP协议进行传递XML格式消息。无论定义还是实现,WEB服务过程中会由服务器提供一个机器可读的描述(通常基于WSDL)以辨识服务器所提供的WEB服务。另外,虽然WSDL不是SOAP服务端点的必要条件,但目前基于Java的主流WEB服务开发框架往往需要WSDL实现客户端的源代码生成。一些工业标准化组织,比如WS-I,就在WEB服务定义中强制包含SOAP和WSDL。 8 | 9 | WEB服务实际上是一组工具,并有多种不同的方法调用之。三种最普遍的手段是: 10 | 11 | - 远程过程调用(RPC) 12 | - 面向服务架构(SOA) 13 | - 表述性状态转移(REST)。 14 | 15 | ##SOAP VS RESTful 16 | 17 | 简单对象访问协议是交换数据的一种协议规范,使用在计算机网络Web服务中,交换带结构信息。SOAP为了简化网页服务器从XML数据库中提取数据时,节省去格式化页面时间,以及不同应用程序之间按照HTTP通信协议,遵从XML格式执行资料互换,使其抽象于语言实现、平台和硬件。 18 | -------------------------------------------------------------------------------- /src/pre/1.pre.md: -------------------------------------------------------------------------------- 1 | 本作品采用[知识共享署名-非商业性使用 4.0 国际许可协议](http://creativecommons.org/licenses/by-nc/4.0/)进行许可。![cc](./images/88x31.png) 2 | 3 | © 2014 [Phodal Huang](http://www.phodal.com). 4 | 5 | #前言## 6 | 7 | 设计物联网系统是件有意思的事情,它需要考虑到软件、硬件、通讯等多个不同方面。通过探索不同的语言,不同的框架,从而形成不同的解决方案。 8 | 9 | 在这里,我们将对设计物联网系统有一个简单的介绍,并探讨如何设计一个最小的物联网系统。 10 | 11 | ##目标读者## 12 | 13 | 目标读者: 初入物联网领域,希望对物联网系统有一个大概的认识和把握,并学会掌握一个基础的物联网系统的设计。 14 | 15 | - 硬件开发人员,对物联网有兴趣。 16 | - 没有web开发经验 17 | - 几乎为0的linux使用经验 18 | - 想快速用于生产环境 19 | - 对硬件了解有限的开发人员。 20 | - 没接触过51、ARM、Arduino 21 | - 想了解以下内容: 22 | - RESTful与IOT 23 | - CoAP协议 24 | - MQTT 25 | 26 | 本文档对一些概念(如)只做了一些基本介绍,以方便读者理解。如果您想进一步了解这些知识,会列出一些推荐书目,以供参考。 27 | 28 | ##不适合人群 29 | 30 | - 如果你是在这方面已经有了丰富经验的开发者。 31 | - 不是为了学习而学习这方面的知识。 32 | -------------------------------------------------------------------------------- /src/futrue/3.2.mqtt.md: -------------------------------------------------------------------------------- 1 | #MQTT 2 | 3 | > MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。 4 | 5 | 早在1999年,IBM的Andy Stanford-Clark博士以及Arcom公司ArlenNipper博士发明了MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)技术[1] 。据Andy Stanford-Clark博士称,MQTT将在今年和明年呈现爆炸式增长。 6 | 7 | 8 | ##Nodejs MQTT 9 | 10 | > [mqtt.js](https://github.com/adamvr/MQTT.js/) is a library for the MQTT protocol, written in JavaScript to be used in node.js. 11 | 12 | ``` javascript 13 | var mqtt = require('mqtt') 14 | 15 | client = mqtt.createClient(1883, 'localhost'); 16 | 17 | client.subscribe('presence'); 18 | client.publish('presence', 'Hello mqtt'); 19 | 20 | client.on('message', function (topic, message) { 21 | console.log(message); 22 | }); 23 | 24 | client.end(); 25 | ``` -------------------------------------------------------------------------------- /help.md: -------------------------------------------------------------------------------- 1 | ##如何编辑 2 | 3 | 只需要一点markdown的知识,别担心这货很简单。 4 | 5 | ###关于目录 6 | 7 | 编辑相关的目录 8 | 9 | - src/ 目录下放的是文档相关的markdown 10 | - src/pre 相当于一些书的前言及简介部分 11 | - images/ 目录下放的是相应的图片 12 | 13 | 生成文档相关的目录 14 | 15 | - template/ 里面放有latex及html的模板 16 | - build/ PDF版,MOBI版,EPUB版 17 | - end/ 毕业设计所在目录 18 | - css/ html版的css 19 | 20 | ###其他文件 21 | 22 | - index.html 你懂的 23 | - Makefile 一个简单的make 24 | - README.md github上显示的内容。 25 | - License.md 协议相关 26 | - CNAME 域名的CNAME 27 | 28 | ##章节及说明 29 | 30 | 以``1.2.anywhere-javascript.md``为例 31 | 32 | 1.2 33 | 34 | - 1说的是第一部分 35 | - 2说的是第二章 36 | 37 | 以此类推 38 | 39 | 目录一共有三个部分 40 | 41 | - 基础部分 42 | - HTTP版部分 43 | - 扩展部分(如coap,mqtt,biz等等) 44 | 45 | ##如何编译 46 | 47 | 如果你不是在类Unix平台上的话——说的是Windows,编译可能会很困难。 48 | 49 | ###编译所需要的软件 50 | 51 | 大致有下面三个 52 | 53 | - latex 54 | - pandoc 55 | - make 56 | 57 | 如果不需要生成pdf版,就不需要latex。 58 | 59 | ###编译命令 60 | 61 | 只需要在目录执行 62 | 63 | make -------------------------------------------------------------------------------- /src/2.1.restful.md: -------------------------------------------------------------------------------- 1 | #设计RESTful API 2 | 3 | > REST从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表征。获得这些表征致使这些应用程序转变了其状态。随着不断获取资源的表征,客户端应用不断地在转变着其状态,所谓表征状态转移。 4 | 5 | 因为我们需要的是一个Machine到Machine沟通的平台,需要设计一个API。而设计一个API来说,RESTful是很不错的一种选择,也是主流的选择。而设计一个RESTful服务,的首要步骤便是设计资源模型。 6 | 7 | ###资源 8 | 9 | 互联网上的一切信息都可以看作是一种资源。 10 | 11 | HTTP Method | Operation Performed 12 | ------------|--------------------- 13 | GET | Get a resource (Read a resource) 14 | POST | Create a resource 15 | PUT | Update a resource 16 | DELETE | Delete Resource 17 | 18 | ##设计RESTful API 19 | 20 | 设计RESTful API是一个有意思的话题。下面是一些常用的RESTful设计原则: 21 | 22 | ##REST关键目标 23 | 24 | - 组件间交互的可伸缩性 25 | - 接口的通用性 26 | - 组件的独立部署 27 | - 通过中间组件来减少延迟、实施安全策略和封装已有系统 28 | 29 | ##判断是否是 RESTful的约束条件 30 | 31 | - 客户端-服务器分离 32 | - 无状态 33 | - 可缓存 34 | - 多层系统 35 | - 统一接口 36 | - 随需代码(可选) 37 | 38 | ##JSON 39 | 40 | ![xml-vs-json](./images/xml-vs-json.png) 41 | -------------------------------------------------------------------------------- /src/pre/2.intro.md: -------------------------------------------------------------------------------- 1 | ##介绍 2 | 3 | 关于内容的选择,这是一个有意思的话题,因为我们很难判断不同的开发者用的是怎样的语言,用的是怎样的框架。 4 | 5 | 于是我们便自作主张地选择了那些适合于理论学习的语言、框架、硬件,去除掉其他一些我们不需要考虑的因素,如语法,复杂度等等。当然,这些语言、框架、硬件也是最流行的。 6 | 7 | - Arduino: 如果你从头开始学过硬件的话,那么你会爱上它的。 8 | - Raspberry PI: 如果你从头编译过GNU/Linux的话,我想你会爱上她的。 9 | - Python: 简单地来说,你可以方便地使用一些扩展,同时代码就表达了你的想法。 10 | - PHP : 这是一门容易部署的语言,我想你只需要在你的Ubuntu机器上,执行一下脚本就能完成安装了。而且,如果你是一个硬件开发者的话,你会更容易地找到其他开发者。 11 | - Javascript : 考虑到javascript这门语言已经无处不在了,而且会更加流行。所以,在这里CoAP、MQTT等版本是基于Nodejs的。 12 | - HTML、CSS : 这是必须的,同样,他们仍然无处不在。 13 | - GNU/Linux: 作为部署到服务器的一部分——你需要掌握他。当然如果你要用WAMP也是可以的。 14 | - CoAP: 用NodeJS构建IOT CoAP物联网 15 | 16 | ###为什么没有C ? 17 | 18 | ``C都不懂还跑过来干嘛``。 19 | 20 | ###为什么不是JAVA ? 21 | 22 | 大有以下两个原因 23 | 24 | - 学习JAVA的人很多,但是它不适合我们集中精力构建与学习,因为无关的代码太多了。 25 | - 之前以及现在,我还是不喜欢JAVA (我更喜欢脚本语言,可以提高工作效率)。 26 | 27 | ##如何阅读 28 | 29 | 这只是一个小小的建议,仅针对于在选择阅读上没有经验的读者。 30 | 31 | 当前状态 | 建议 | 32 | | ------- | -----| 33 | 软件初学者| 从头阅读 34 | 硬件开发者| 从头阅读 35 | 没有web经验的开发者| 从第二部分开始 36 | 37 | 我们会在前面十章里简单介绍一些必要的基础知识,这些知识将会在后面我们构建物联网系统时用到。 38 | -------------------------------------------------------------------------------- /src/1.9.server.md: -------------------------------------------------------------------------------- 1 | #Server 一切皆为服务 2 | 3 | ##服务器 4 | 5 | 服务器(Server)指: 6 | 7 | - 一个管理资源并为用户提供服务的计算机软件,通常分为文件服务器(能使用户在其它计算机访问文件),数据库服务器和应用程序服务器。 8 | - 运行以上软件的计算机,或称为网络主机(Host)。 9 | - 一般来说,服务器通过网络对外提供服务。可以通过Intranet对内网提供服务,也可以通过Internet对外提供服务。 10 | 11 | ##Web服务器 12 | 13 | WEB服务器也称为WWW(WORLD WIDE WEB)服务器,主要功能是提供网上信息浏览服务。 WWW 是 Internet的多媒体信息查询工具,是 Internet 上近年才发展起来的服务,也是发展最快和目前用的最广泛的服务。正是因为有了WWW工具,才使得近年来 Internet 迅速发展,且用户数量飞速增长。 14 | 15 | ##LNMP 16 | 17 | ![LNMP](./images/lnmp.gif) 18 | 19 | Linux+Nginx+MySQL+PHP 20 | 21 | > Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru站点开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。2011年6月1日,nginx 1.0.4发布。 22 | 23 | > MySQL 是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司。MySQL是最流行的关系型数据库管理系统,在WEB应用方面MySQL是最好的RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。 24 | 25 | > PHP于1994年由Rasmus Lerdorf创建,刚刚开始是Rasmus Lerdorf为了要维护个人网页而制作的一个简单的用Perl语言编写的程序。这些工具程序用来显示 Rasmus Lerdorf 的个人履历,以及统计网页流量。后来又用C语言重新编写,包括可以访问数据库。他将这些程序和一些表单直译器整合起来,称为 PHP/FI。PHP/FI 可以和数据库连接,产生简单的动态网页程序。 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pandoc -s -V geometry:margin=1in --number-sections --highlight-style pygments -S --toc -c css/vendor.css -B template/head.html src/pre/*.md src/*.md src/end/*.md -o index.html 3 | 4 | iot: 5 | pandoc -s -V geometry:margin=1in --number-sections --highlight-style pygments -S --toc -c css/vendor.css -B template/head.html end/iot.md -o iot.html 6 | 7 | chapter: 8 | find src/ -name \*.md -type f -exec pandoc -s -V geometry:margin=1in --number-sections --highlight-style pygments -S --toc -c css/vendor.css -B template/head-chapter.html -o {}.html {} \; 9 | mv src/*/*.html build/ 10 | mv src/*.html build/ 11 | 12 | epub: 13 | pandoc -s -V geometry:margin=1in --number-sections --highlight-style pygments -S --toc -c css/vendor.css -B template/headpdf.html src/pre/*.md src/*.md src/end/*.md -o build/pdf.html 14 | pandoc build/pdf.html -o build/designiot.epub 15 | 16 | release: 17 | pandoc -s -V geometry:margin=1in --number-sections --highlight-style pygments -S --toc -c css/vendor.css -B template/headpdf.html src/pre/*.md src/*.md src/end/*.md -o build/pdf.html 18 | pandoc --template=template/template.tex build/pdf.html -o build/iot.pdf --latex-engine=xelatex 19 | pandoc build/pdf.html -o build/designiot.epub 20 | pandoc build/pdf.html -o build/designiot.mobi 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 《[一步步搭建物联网系统](http://phodal.github.io/designiot/)》 2 | === 3 | 4 | 《自己动手设计物联网》现已出版: 5 | 6 | ![Designiot](./designiot.jpg) 7 | 8 | 立即购买:[亚马逊](https://www.amazon.cn/dp/B01IBZWTWW/ref=wl_it_dp_o_pC_nS_ttl?_encoding=UTF8&colid=BDXF90QZX6WX&coliid=I19EB97K0GNLW8)、[京东](http://search.jd.com/Search?keyword=%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E8%AE%BE%E8%AE%A1%E7%89%A9%E8%81%94%E7%BD%91&enc=utf-8&wq=%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E8%AE%BE%E8%AE%A1%E7%89%A9%E8%81%94%E7%BD%91&pvid=k24y6hri.l4xi28)、[当当](http://product.dangdang.com/24000878.html) 9 | 10 | **在线查看**:[一步步搭建物联网系统](http://phodal.github.io/designiot/),主题:[Mifa Design](https://github.com/phodal/mifa) 11 | 12 | Android App版: 13 | 14 | 15 | Get it on Google Play 17 | 18 | 19 | ## 作者名单 20 | 21 | Github | Name 22 | |--------| ---------| 23 | [phodal](https://github.com/phodal) |[Phodal Huang](http://www.phodal.com) 24 | [Lboyve](https://github.com/Lboyve) | Xiaobing WANG 25 | 26 | ## License 27 | 28 | [![Phodal's Book](http://brand.phodal.com/shields/book-small.svg)](https://www.phodal.com/) 29 | 30 | © 2014~2016 [Phodal Huang](http://www.phodal.com). 31 | 32 | 本作品采用[知识共享署名-非商业性使用 4.0 国际许可协议](http://creativecommons.org/licenses/by-nc/4.0/)进行许可。 33 | 34 | [待我代码编成,娶你为妻可好](http://www.xuntayizhan.com/blog/ji-ke-ai-qing-zhi-er-shi-dai-wo-dai-ma-bian-cheng-qu-ni-wei-qi-ke-hao-wan/) 35 | 36 | -------------------------------------------------------------------------------- /src/3.1.iot-coap.md: -------------------------------------------------------------------------------- 1 | 2 | ##使用IoT-CoAP构建物联网 3 | 4 | (``注意``:windows系统npm install失败时,需要自己建立一个C:\Documents and Settings\[USERNAME]\Application Data\npm 文件) 5 | 6 | ```bash 7 | npm install iot-coap 8 | ``` 9 | 10 | 1.新建**index.js** 11 | 12 | ``注意``: 如果已经存在一个index.js文件,请将下面内容添加到文件末尾(create index.js, and add) 13 | 14 | ```javascript 15 | var iotcoap = require('iot-coap'); 16 | 17 | iotcoap.run(); 18 | iotcoap.rest.run(); 19 | ``` 20 | 21 | ``注意``:在db配置可以选择mongodb和sqlite3,替换所需要的数据库即可。(you can choice db on iot.js with 'sqlite' or 'mongodb') 22 | 23 | 2.创建**iot.js** 24 | 25 | ```javascript 26 | exports.config = { 27 | "db_name": "iot.db", 28 | "mongodb_name": "iot", 29 | "mongodb_documents": "iot", 30 | "db": "mongodb", 31 | "table_name": "basic", 32 | "keys":[ 33 | "id", 34 | "value", 35 | "sensors1", 36 | "sensors2" 37 | ], 38 | "db_table": "id integer primary key, value text, sensors1 float, sensors2 float", 39 | "mongodb_init":[ 40 | { 41 | id: 1, 42 | value: "is id 1", 43 | sensors1: 19, 44 | sensors2: 20 45 | }, 46 | { 47 | id: 2, 48 | value: "is id 2", 49 | sensors1: 20, 50 | sensors2: 21 51 | } 52 | ], 53 | "init_table":[ 54 | "insert or replace into basic (id,value,sensors1,sensors2) VALUES (1, 'is id 1', 19, 20);", 55 | "insert or replace into basic (id,value,sensors1,sensors2) VALUES (2, 'is id 2', 20, 21);" 56 | ], 57 | "query_table":"select * from basic;", 58 | "rest_url": "/id/:id", 59 | "rest_post_url": "/", 60 | "rest_port": 8848 61 | }; 62 | ``` 63 | 64 | 3.运行(run) 65 | 66 | ```bash 67 | node index.js 68 | ``` 69 | 70 | show: 71 | 72 | ```bash 73 | coap listening at coap://0.0.0.0:5683 74 | restify listening at http://0.0.0.0:8848 75 | ``` 76 | -------------------------------------------------------------------------------- /src/1.8.rpi.md: -------------------------------------------------------------------------------- 1 | #Raspberry Pi 2 | 3 | ![Raspberry Pi](./images/rpi.jpg) 4 | 5 | ##Geek的盛宴 6 | 7 | Raspberry Pi是一款针对电脑业余爱好者、教师、小学生以及小型企业等用户的迷你电脑,预装Linux系统,体积仅信用卡大小,搭载ARM架构处理器,运算性能和智能手机相仿。在接口方面,Raspberry Pi提供了可供键鼠使用的USB接口,此外还有千兆以太网接口、SD卡扩展接口以及1个HDMI高清视频输出接口,可与显示器或者TV相连。 8 | 9 | Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。 10 | 11 | Raspberry Pi相比于一般的ARM开发板来说,由于其本身搭载着Linux操作系统,可以用诸如Python、Ruby或Bash来执行脚本,而不是通过编译程序来运行,具有更高的开发效率。 12 | 13 | ##Raspberry Pi 初始化 14 | 15 | 今天的Raspbian默认已经安装``openssh-server``,并默认开启了OpenSSH-Server。 16 | 17 | 接着我们就可以看到系统启动了,要我们输入用户名和密码 18 | 19 | ```bash 20 | Raspbian GNU/Linux 7 raspberrypi ttyAMA0 21 | 22 | raspberrypi login: pi 23 | Password: 24 | Last login: Sat Apr 26 05:58:07 UTC 2014 on ttyAMA0 25 | Linux raspberrypi 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l 26 | 27 | The programs included with the Debian GNU/Linux system are free software; 28 | the exact distribution terms for each program are described in the 29 | individual files in /usr/share/doc/*/copyright. 30 | 31 | Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent 32 | permitted by applicable law. 33 | ls 34 | 35 | NOTICE: the software on this Raspberry Pi has not been fully configured. Please run 'sudo raspi-config' 36 | ``` 37 | 38 | 然后 39 | 40 | ```bash 41 | sudo raspi-config 42 | ``` 43 | 44 | 选择第一个,下面就可以继续了 45 | 46 | ``` 47 | Expand Filesystem Ensures that all of the SD card s 48 | ``` 49 | 50 | 接着重启后,便可以扩展SD卡成功。 51 | 52 | 注: Raspbian与一般的Debian系统使用起来区别不是太大(ps:命令上),由于CPU是不同的架构,在编译上可能有所区别。通常PC上的软件需要重新编译才能在RPi上运行,所以如果可以用apt-get安装的话,就不要自己编译了。 53 | 54 | ##Raspberry Pi GPIO 55 | 56 | > General Purpose Input Output (通用输入/输出)简称为GPIO,或总线扩展器,利用工业标准I2C、SMBus或SPI接口简化了I/O口的扩展。当微控制器或芯片组没有足够的I/O端口,或当系统需要采用远端串行通信或控制时,GPIO产品能够提供额外的控制和监视功能。 57 | 58 | ![GPIO](./images/gpio.png) 59 | -------------------------------------------------------------------------------- /template/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 一步步搭建物联网系统(教你设计物联网系统) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 19 | 22 | 23 |
14 | 15 | 17 | 18 | 20 | 21 |
24 |

纸质版《自己动手设计物联网》现已出版

25 | 26 |

Designiot

27 | 28 |

立即购买:亚马逊京东

当当 29 | 30 | 31 |

一步步搭建物联网系统(教你设计物联网系统)

32 | 源自毕业论文:基于REST服务的最小物联网系统设计 33 | 41 | 42 | -------------------------------------------------------------------------------- /src/4.0.easyiot.md: -------------------------------------------------------------------------------- 1 | 2 | #简单物联网 3 | 4 | 到这时,我们算搭建了一个简单的REST服务了。接着我们可以简单的做一个最小的物联网系统,将我们的单片机、MCU等等连上网。 5 | 6 | ![硬件结构图](./images/arch.jpeg) 7 | 8 | 考虑到如果我们只是单一连接各个节点,那么系统的结构图,同下所示 9 | 10 | ![全连接](./images/fullconnected.png) 11 | 12 | 下面的星形结构图类似于我们在接下来所要构建的系统 13 | 14 | ![星形结构图](./images/star.png) 15 | 16 | 一个用于控制真实电器的硬件实物图 17 | 18 | ![简单实物图](./images/hardware.jpg) 19 | 20 | ##硬件通信 21 | 22 | ###串口通信 23 | 24 | Arduino与Raspberry Pi通过串口通信的方式实现通信,相互传输所需要的数据,Raspberry Pi将资源传于互联网上对应的接口,接口可以在互联网上被访问。Laravel框架构架于服务器之上,将Raspbery Pi获取过来的数据存储于MySQL数据,再以REST服务的方式共享数据,互联网上的其他设备便可以通过网络来访问这些设备。Ajax用于将后台的数据以不需要刷新的方式传递到网站前台,通过HighCharts框架显示给终端用户。 25 | 26 | ####Python 27 | 28 | 1.在Windows中的串口通常是``COM1``,``COM0``等等 29 | 30 | ```python 31 | ser=serial.Serial("COM0",9600) 32 | ``` 33 | 34 | 2.Mac OS系统中位于/dev目录下,名字类似于``tty.usbmodem1451``。 35 | 36 | ``` python 37 | serial.Serial("/dev/tty.usbmodem1451",9600) 38 | ``` 39 | 40 | 3.在Linux内核的系统中虚拟串口用的节点是ttyACM,位于/dev目录下。 41 | 42 | ``` python 43 | serial.Serial("/dev/ttyACM0",9600) 44 | ``` 45 | 46 | > 串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能 47 | 的电路,我们称为串行接口电路。 48 | 49 | 便是打开这个设备,以9600的速率传输数据。 50 | 51 | 程序框架如下所示: 52 | 53 | ![Raspberry Pi](./images/raspberrypi_flow.png) 54 | 55 | 代码如下: 56 | 57 | ```python 58 | import json 59 | import urllib2 60 | import serial 61 | import time 62 | 63 | url="http://www.xianuniversity.com/athome/1" 64 | 65 | while 1: 66 | try: 67 | date=urllib2.urlopen(url) 68 | result=json.load(date) 69 | status=result[0]["led1"] 70 | ser=serial.Serial("/dev/ttyACM0",9600) 71 | if status==1 : 72 | ser.write("1") 73 | elif status==0: 74 | ser.write("0") 75 | time.sleep(1) 76 | except urllib2.URLError: 77 | print "Bad URL or timeout" 78 | ``` 79 | 80 | ![python返回json数据](./images/getjson.png) 81 | 82 | 系统还需要对上面的数据进行处理,只拿其中的结果 83 | 84 | ![python处理完后的结果](./images/origin.png) 85 | 86 | 当改变led的状态后,便可以得到下面的结果 87 | 88 | ![改变状态后的结果](./images/change.png) 89 | 90 | ####Ruby 91 | 92 | 如果你用的是Ruby的话,可以尝试使用``serialport`` 93 | 94 | 安装 95 | 96 | ```bash 97 | sudo gem install serialport 98 | ``` 99 | 100 | 代码大致如下 101 | 102 | ```Ruby 103 | require 'serialport' 104 | sp = SerialPort.new "/dev/ACM0", 9600 105 | sp.write "1" 106 | ``` 107 | 108 | 注意: 根据相关的系统修改相关的代码。 109 | 110 | 111 | ##硬件 112 | 113 | ###Arduino 114 | 115 | 这样我们在我们的Arduino上所要做的便是,读取串口的结果并控制IO口。 116 | 117 | ```c 118 | int ledPort=13; 119 | 120 | void setup() { 121 | Serial.begin(9600); 122 | pinMode(ledPort,OUTPUT); 123 | } 124 | 125 | int serialData; 126 | void loop() { 127 | String inString = ""; 128 | while (Serial.available()> 0) 129 | { 130 | int inChar = Serial.read(); 131 | if (isDigit(inChar)) { 132 | inString += (char)inChar; 133 | } 134 | serialData=inString.toInt(); 135 | Serial.print(serialData); 136 | } 137 | if(serialData==1){ 138 | digitalWrite(ledPort,HIGH); 139 | }else{ 140 | digitalWrite(ledPort,LOW); 141 | } 142 | } 143 | ``` 144 | 145 | 如果结果是1的话,就让13口为高电平,也就是让灯亮起来。 146 | 147 | ###继电器 148 | 149 | > 继电器(英文名称:relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。故在电路中起着自动调节、安全保护、转换电路等作用。 150 | 151 | 在这里我们可以默认为我们想要为单片机的5V电压控制220V的电器。 152 | 153 | 最后我们便可以通过些来控制灯的开和关。 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /src/1.6.arduino.md: -------------------------------------------------------------------------------- 1 | #Arduino 极客的玩具 2 | 3 | ##极客的玩具 4 | 5 | Arduino,是一个开放源代码的单芯片微电脑,它使用了Atmel AVR单片机,采用了基于开放源代码的软硬件平台,构建于开放源代码 simple I/O 接口板,并且具有使用类似Java,C 语言的Processing/Wiring开发环境。 6 | 7 | Arduino开发板封装了常用的库到开发环境中,可以让用户在开发产品时,将主要注意力放置于所需要实现的功能上,而不是开发的过程中。在为Arduino写串口程序时,我们只需要用Serial.begin(9600)以9600的速率初始化串口,而在往串口发送数据时,可以用Serial.write('1')的方式向串口发送字串'1'。 8 | 9 | Arduino的出现很大程度上降低了电子制作的难度,初学者甚至不懂编程也可以上手Arduino,这也是它的魅力所在。 10 | 11 | ##硬件熟悉## 12 | 13 | 为了满足各种需求,Arduino团队设计了很多款开发板,如UNO、Pro mini、Mega2560、Due、Leonardo、Yún、Pro、Fio、Nano等十几种 开发板和扩展板。最适合初学者的一款是Arduino UNO 。下图是Arduino UNO 的外观图: 14 | 15 | ![UNO](http://ebook.designiot.cn/images/uno.png) 16 | 17 | 注:后面的程序也是基于Arduino UNO开发板来讲解。 18 | 19 | ##开发环境## 20 | 21 | ![Arduino](http://ebook.designiot.cn/images/arduino.png) 22 | 23 | 开发环境如上图,十分简洁,编写代码需要知道两个基本的函数: 24 | 25 | ```cpp 26 | void setup(){ 27 | 28 | } 29 | 30 | void loop(){ 31 | 32 | } 33 | ``` 34 | 35 | ``setup()``函数用于初始化(如GPIO初始化,串口初始化,定时器初始化等)特点是只执行一次;``loop()``函数是一个死循环,可以看做C语言的``while(1)``函数。 36 | 37 | ##点亮一个LED## 38 | 39 | 对初学者来说,点亮led已成为入门必修课,使用Arduino控制led十分简单,并且很容易理解。 40 | 使用到的函数: 41 | 42 | * pinMode(pin,mode) 43 | * digitalWrite(pin,value) 44 | 45 | 上一段代码分析: 46 | 47 | ```cpp 48 | int led=13; 49 | 50 | void setup() 51 | { 52 | pinMode(led,OUTPUT); 53 | } 54 | void loop() 55 | { 56 | digitalWrite(led,HIGH); 57 | delay(1000); 58 | digitalWrite(led,LOW); 59 | delay(1000); 60 | } 61 | ``` 62 | 63 | 该程序实现Arduino单片机13号引脚以1S时间电平翻转,如果外接一个led,就可以看到led以1S的间隔闪烁;函数``pinMode()``有两个参数pin、value,pin参数用来指定引脚号,本程序中设置为13号引脚,mode用于设置引脚模式,有三个值: 64 | 65 | - ``INPUT`` 66 | - ``OUTPUT`` 67 | - ``INPUT_PULLUP`` 68 | 69 | 表示让某一个IO引脚作输入,反之, 70 | 71 | - ``OUTPUT``则使一个IO引脚做输出 72 | - ``INPUT_PULLUP``则配置一个IO引脚具有上拉输入功能(上拉电阻的目的是为了保证在无信号输入时输入端的电平为高电平),从英文意思也能很直观的看出来。 73 | 74 | 理解了``pinMode()``函数,``digitalWrite()``就很容易理解啦,value的取值有两个``HIGH``、``LOW``,``HIGH``表示让某一个引脚输出高电平,反之,``LOW``则使某一个引脚输出低电平。 75 | 程序中还是用到``delay(ms)``函数,它表示延时多少毫秒,例如延时500 ms ,直接调用``delay(500);``就可以了。 76 | 77 | 如果你仔细查看我的描述,你会发现我没有讲13号引脚怎么来的,是这样的:Arduino团队为了简化对引脚描述,对每个引脚都进行了编号,以UNO开发板为例,可以发现开发板排座的附近有对应的白颜色的数字,那便是所有的引脚编号,A0~A5是6路ADC输入引脚,0-13表示13路基本IO,数字前面的``~``表示该引脚具有PWM功能。如果要使用某一引脚,只需要知道引脚编号就可编写相应代码进行操作。 78 | 79 | 例如``digitalWrite(2,LOW)``表示向2号引脚输出低电平。其他操作类似,是不是so easy ^-^ ! 80 | 81 | ##串口通信## 82 | 83 | 使用到的基本函数: 84 | 85 | - Serial.begin() 86 | - Serial.write() 87 | - Serial.read() 88 | - Serial.available() 89 | 90 | 在此项目中需要使用串口,Arduino串口初始化使用``Serial.begin(9600);``,其传输波特率为9600,其他波特率也行,函数位于``setup()``中,之后可以使用``Serial.read()``、``Serial.write()``读入一个字符,输出一个字符,使用``Serial.print()``输出字符串.代码如下: 91 | 92 | ```cpp 93 | char ch='1'; 94 | void setup() 95 | { 96 | Serial.begin(9600); 97 | } 98 | void loop() 99 | { 100 | Serial.write(ch); 101 | while(1) 102 | { 103 | if(Serial.available()) 104 | { 105 | ch = Serial.read(); 106 | Serial.print(ch); 107 | } 108 | } 109 | } 110 | ``` 111 | 112 | 以上程序实现字符的输出(Serial.write(),Serial.print())和读入(Serial.read())。如果需要了解更多,可以参考:[Arduino官网](www.arduino.cc) 113 | 114 | ###关于Arduino Setup() 115 | 116 | 如果你对Arduino的Setup很疑惑的话,可以看看这里。下面Arduino源码目录中的main函数: 117 | 118 | ```cpp 119 | #include 120 | 121 | int main(void) 122 | { 123 | init(); 124 | setup(); 125 | for (;;) { 126 | loop(); 127 | if (serialEventRun) serialEventRun(); 128 | } 129 | return 0; 130 | } 131 | ``` 132 | 133 | ![hwcnt](./images/hwcnt.png) 134 | 135 | -------------------------------------------------------------------------------- /src/2.2.init_env.md: -------------------------------------------------------------------------------- 1 | #环境准备 2 | 3 | ##Laravel 4 | 5 | > Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。 6 | 7 | - RESTful 路由: 通过简单的闭包就能响应HTTP请求。帮你快速开始构建非凡的应用。 8 | - 强大的数据操纵能力: Laravel自带了强大的Eloquent ORM 和迁移工具。能够完美的与MySQL、Postgres、SQL Server 和 SQLite协同工作。 9 | - 优雅的模版引擎: PHP代码或轻量级的Blade模版引擎都可无缝融合。Blade模版可以继承,并且拥有极快的解析速度。相信你会喜欢它的。 10 | - 为明天做准备: 构建大型的企业级应用或者只是提供简单的JSON API;书写强大的控制器或轻巧的RESTful路由,Laravel适应所有级别的开发工作。 11 | - 可靠的基石: Laravel 的基石是数个Symfony组件,这些经过千锤百炼、可靠的组件为你的应用提供坚实的基础。 12 | - 基于Composer管理器: Composer 是一套帮你管理第三方扩展包的工具。能够让你迅速在 Packagist 中找到需要的扩展包。 13 | - 强大的社区支持: 无论你是一个PHP新手还是经验丰富的架构师,都能在社区中找到需要的知识。你可以在IRC中讨论Idea,或者在论坛中发布问题。 14 | - 测试、重构: Laravel 从开始就将测试作为重点功能。我们提供了灵活的IoC容器,集成了PHPUnit 测试工具。不用担心,这些都很容易上手。 15 | 16 | ###为什么是 Laravel 17 | 18 | - 因为个人喜爱,你也可以用 Ruby On Rails来搭建这样一个功能,或者是Java。 19 | - PHP在我的服务器上运行得挺不错的,而且我又不需要重新去写配置那些配置。 20 | - Laravel 可以简单的开发我们所需要的功能,换句话说他是 PHP 世界的 Ruby On Rails。 21 | 22 | 这里不会再重述之前的问题,这里只是将需要的步骤一个个写下来,然后丢到这里好好说一下。至于RESTful是什么,前面已经介绍了,就不再重复了。那么下面,我们就用Laravel来搭建一个平台给物联网用的。 23 | 24 | ##安装 Laravel 25 | 26 | ###GNU/Linux安装Composer 27 | 28 | GNU/Linux Ubuntu/OpenSUSE下可以执行 29 | 30 | $ curl -sS https://getcomposer.org/installer | php 31 | 32 | ####Windows安装Composer 33 | 34 | 请直接下载 35 | 36 | [Composer-Setup][composer] 37 | 38 | ####Mac OS 39 | 40 | 1.安装Composer 41 | 42 | ```bash 43 | brew install homebrew/php/composer 44 | ``` 45 | 46 | 2.安装Laravel 47 | 48 | ```bash 49 | composer global require "laravel/installer=~1.1" 50 | ``` 51 | 52 | 3.创建Laravel工程 53 | 54 | ```bash 55 | composer create-project laravel/laravel your-project-name --prefer-dist 56 | ``` 57 | 58 | ####Mac OS 59 | 60 | 1.下载laravel.phar 61 | 62 | ```bash 63 | wget http://laravel.com/laravel.phar 64 | ``` 65 | 66 | 2.重命名 67 | 68 | ```bash 69 | mv laravel.phar laravel 70 | ``` 71 | 72 | 3.移动到bin中 73 | 74 | ```bash 75 | sudo mv laravel /usr/local/bin 76 | ``` 77 | 78 | 4.创建项目 79 | 80 | ```bash 81 | laravel new blog 82 | ``` 83 | 84 | ##MySQL 85 | 86 | ###安装MySQL 87 | 88 | ``出于某些原因,我建议用MariaDB替换MySQL,如果你"真正"需要mysql,将mariadb替换为mysql`` 89 | 90 | ps: 在下文中我会继续用MySQL,而不是MariaDB,MairaDB是MySQL的一个分支,真正的开源分支。 91 | 92 | Ubuntu/Debian/Mint 93 | 94 | ```bash 95 | $ sudo apt-get install mariadb-server 96 | ``` 97 | 98 | Fedora/Centos 99 | 100 | ```bash 101 | $ sudo yum install mariadb-server 102 | ``` 103 | 104 | openSUSE 105 | 106 | ```bash 107 | $ sudo zypper install mariadb-server 108 | ``` 109 | 110 | Mac OS 111 | 112 | ```bash 113 | $ brew install mariadb 114 | ``` 115 | 116 | ###配置MySQL 117 | 118 | 修改database.php 119 | 120 | ```bash 121 | app/config/database.php 122 | ``` 123 | 124 | 要修改的就是这个 125 | 126 | ```php 127 | 'mysql' => array( 128 | 'driver' => 'mysql', 129 | 'host' => 'localhost', 130 | 'database' => 'iot', 131 | 'username' => 'root', 132 | 'password' => '940217', 133 | 'charset' => 'utf8', 134 | 'collation' => 'utf8_unicode_ci', 135 | 'prefix' => '', 136 | ), 137 | ``` 138 | 139 | 如果你已经有phpmyadmin,似乎对你来说已经很简单了,如果没有的话,就直接用 140 | 141 | ```bash 142 | $ mysql -uroot -p 143 | ``` 144 | 来创建一个新的 145 | 146 | ```sql 147 | CREATE DATABASE IF NOT EXISTS iot default charset utf8 COLLATE utf8_general_ci; 148 | ``` 149 | 150 | [composer]: https://getcomposer.org/Composer-Setup.exe 151 | 152 | 数据库的目的在于存储数据等等的闲话这里就不多说了,创建一个RESTful的目的在于产生下面的JSON格式数据,以便于我们在Android、Java、Python、jQuery等语言框架或者平台上可以调用,最主要的是可以直接用Ajax来产生更炫目的效果。 153 | 154 | ```javascript 155 | { 156 | "id": 1, 157 | "temperature": 14, 158 | "sensors1": 12, 159 | "sensors2": 12, 160 | "led1": 0 161 | } 162 | ``` 163 | -------------------------------------------------------------------------------- /src/1.1.anywhere-html.md: -------------------------------------------------------------------------------- 1 | 某一天,正走在回学校的路上的我突然想到:“未来将会是一个科技的时代——虽然现在也是——只是在未来,科技将会无处不在。如果我们依旧对周围这些无处不在的代码一无所知的话,或许我们会成为黑客帝国之中被控制的普通人。”于是开始想着,有一天人们会像学习一门语言一样开始学习编程,直到又有一天我看到了学习编程如同学习一门语言的说法。这又恰好在我做完最小物联网系统之后,算是一个有趣的时间点,我开始想着像之前做最小物联网系统的那些步骤一样,写一个简单的入门。也可以补充好之前在这个最小物联网系统缺失的那些东西,给那些正在开始试图去解决编程问题的人。 2 | 3 | 让我们先从身边的语言下手,也就是现在无处不在的html+javascript+css。 4 | 5 | #无处不在的HTML 6 | 7 | 之所以从html开始,是因为我们不需要配置一个复杂的开发环境,也许你还不知道开发环境是什么东西,不过这也没关系,毕竟这些知识需要慢慢的接触才能有所了解,尤其是对于普通的业余爱好者来说,当然,对于专业选手言自然不是问题。HTML是Web的核心语言,也算是比较基础的语言。 8 | 9 | ##html的hello,world 10 | Hello,world是一个传统,所以在这里也遵循这个有趣的传统,我们所要做的事情其实很简单,虽然也有一点点hack的感觉。——让我们先来新建一个文并命名为"helloworld.html"。 11 | 12 | (PS:大部分人应该都是在windows环境下工作的,所以你需要新建一个文本,然后重命名,或者你需要一个编辑器,在这里我们推荐用sublime text。破解不破解,注册不注册都不会对你的使用有太多的影响。) 13 | 14 | 1. 新建文件 15 | 16 | 2. 输入
hello,world
17 | 18 | 3. 保存为->"helloworld.html", 19 | 20 | 4. 双击打开这个文件。 正常情况下都应该是用你的默认浏览器打开。只要是一个正常工作的现代浏览器,都应该可以看到上面显示的是"Hello,world"。 21 | 22 | 这才是最短的hello,world程序,但是呢?在ruby中会是这样子的 23 | 24 | ``` bash 25 | 2.0.0-p353 :001 > p "hello,world" 26 | "hello,world" 27 | => "hello,world" 28 | 2.0.0-p353 :002 > 29 | ``` 30 | 31 | 等等,如果你了解过html的话,会觉得这一点都不符合语法规则,但是他工作了,没有什么比安装完Nginx后看到It works!更让人激动了。 32 | 33 | 遗憾的是,它可能无法在所有的浏览器上工作,所以我们需要去调试其中的bug。 34 | 35 | ###调试hello,world### 36 | 我们会发现我们的代码在浏览器中变成了下面的代码,如果你和我一样用的是chrome,那么你可以右键浏览器中的空白区域,点击审查元素,就会看到下面的代码。 37 | 38 | ``` html 39 | 40 | 41 | hello,world 42 | 43 | ``` 44 | 45 | 这个才是真正能在大部分浏览器上工作的代码,所以复制它到编辑器里吧。 46 | 47 | ###说说hello,world## 48 | 我很不喜欢其中的<\*>,但是我也没有找到别的方法来代替它们,所以这是一个设计得当的语言。甚至大部分人都说这算不上是一门真正的语言,不过html的原义是 49 |
超文本标记语言
50 | 所以我们可以发现其中的关键词是标记——markup,也就是说html是一个markup,head是一个markup,body也是一个markup。 51 | 52 | 然而,我们真正工作的代码是在body里面,至于为什么是在这里面,这个问题就太复杂了。打个比方来说: 53 | 54 | 1. 我们所使用的汉语是人类用智慧创造的,我们所正在学的这门语言同样也是人类创造的。 55 | 56 | 2. 我们在自己的语言里遵循着桌子是桌子,凳子是凳子的原则,很少有人会问为什么。 57 | 58 | 59 | ###想用中文?### 60 | 所以我们也可以把计算机语言与现实世界里用于交流沟通的语言划上一个等号。而我们所要学习的语言,并不是我们最熟悉的汉语语言,所以我们便觉得这些很复杂,但是如果我们试着用汉语替换掉上面的代码的话 61 | ```HTML 62 | <语言> 63 | <头><结束头> 64 | <身体>你好,世界<结束身体> 65 | <结束语言> 66 | ``` 67 | 这看上去很奇怪,只是因为是直译过去的原因,也许你会觉得这样会好理解一点,但是输入上可就一点儿也不方便,因为这键盘本身就不适合我们去输入汉字,同时也意味着可能你输入的会有问题。 68 | 69 | 让我们把上面的代码代替掉原来的代码然后保存,打开浏览器会看到下面的结果 70 | ```HTML 71 | <语言> <头><结束头> <身体>你好,世界<结束身体> <结束语言> 72 | ``` 73 | 74 | 更不幸的结果可能是 75 | 76 | ```HTML 77 | <璇█> <澶�><缁撴潫澶�> <韬綋>浣犲ソ锛屼笘鐣�<缁撴潫韬綋> <缁撴潫璇█> 78 | ``` 79 | 80 | 这是一个编码问题,对中文支持不友好。 81 | 82 | 我们把上面的代码改为和标记语言一样的结构 83 | 84 | ```HTML 85 | <语言> 86 | <头> 87 | <身体>你好,世界 88 | <结束语言> 89 | ``` 90 | 91 | 于是我们看到的结果便是 92 | 93 | ```HTML 94 | <语言> <头> <身体>你好,世界 95 | ``` 96 | 97 | 被chrome浏览器解析成什么样了? 98 | 99 | ``` html 100 | <语言> 101 | <头> 102 | <身体>你好,世界 103 | 104 | 105 | ``` 106 | 107 | 以 108 | 109 | 110 | 结尾的是注释,写给人看的代码,不是给机器看的,所以机器不会去理解这些代码。 111 | 112 | 但是当我们把代码改成 113 | 114 | ```HTML 115 | 你好世界 116 | ``` 117 | 118 | 浏览器上面显示的内容就变成了 119 | 120 | ```HTML 121 | 你好世界 122 | ``` 123 | 124 | 或许你会觉得很神奇,但是这一点儿也不神奇,虽然我们的中文语法也遵循着标记语言的标准,但是我们的浏览器不支持中文标记。 125 | 126 | 结论: 127 | 128 | 1. 浏览器对中文支持不友好。 129 | 2. 浏览器对英文支持友好。 130 | 131 | 刚开始的时候不要对中文编程有太多的想法,这是很不现实的: 132 | 133 | 1. 现有的系统都是基于英语语言环境构建的,对中文支持不是很友好。 134 | 2. 中文输入的速度在某种程度上来说没有英语快。 135 | 136 | 我们离开话题已经很远了,但是这里说的都是针对于那些不满于英语的人来说的,只有当我们可以从头构建一个中文系统的时候才是可行的,而这些就要将cpu、软件、硬件都包含在内,甚至我们还需要考虑重新设计cpu的结构,在某种程度上来说会有些不现实。或许,需要一代又一代人的努力。忘记那些吧,师夷长之技以治夷。 137 | 138 | ##其他html标记## 139 | 140 | 添加一个标题, 141 | 142 | ```HTML 143 | 144 | 145 | 标题 146 | 147 | hello,world 148 | 149 | ``` 150 | 151 | 我们便可以在浏览器的最上方看到“标题”二字,就像我们常用的淘宝网,也包含了上面的东西,只是还包括了更多的东西,所以你也可以看懂那些我们可以看到的淘宝的标题。 152 | 153 | ``` html 154 | 155 | 156 | 标题 157 | 158 | 159 | hello,world 160 |

大标题

161 |

次标题

162 |

...

163 | 167 | 168 | 169 | ``` 170 | 171 | 更多的东西可以在一些书籍上看到,这边所要说的只是一次简单的语言入门,其他的东西都和这些类似。 172 | 173 | ###美妙之处### 174 | 我们简单地上手了一门不算是语言的语言,浏览器简化了这其中的大部分过程,虽然没有C和其他语言来得有专业感,但是我们试着去开始写代码了。我们可能在未来的某一篇中可能会看到类似的语言,诸如python,我们所要做的就是 175 | 176 | ```bash 177 | $ python file.py 178 | =>hello,world 179 | ``` 180 | 181 | 然后在终端上返回结果。只是因为在我看来学会html是有意义的,简单的上手,然后再慢慢地深入,如果一开始我们就去理解指针,开始去理解类。我们甚至还知道程序是怎么编译运行的时候,在这个过程中又发生了什么。虽然现在我们也没能理解这其中发生了什么,但是至少展示了 182 | 183 | 1. 中文编程语言在当前意义不大,不现实,效率不高兼容性差 184 | 2. 语言的语法是固定的。(ps:虽然我们也可以进行扩充,我们将会在后来支持上述的中文标记。) 185 | 3. 已经开始写代码,而不是还在配置开发环境。 186 | 4. 随身的工具才是最好的,最常用的code也才是实在的。 187 | 188 | 189 | ###更多### 190 | 我们还没有试着去解决“某商店里的糖一颗5块钱,小明买了3颗糖,小明一共花了多少钱”的问题。也就是说我们学会的是一个还不能解决实际问题的语言,于是我们还需要学点东西,比如javascript,css。我们可以将Javascript理解为解决问题的语言,html则是前端显示,css是配置文件,这样的话,我们会在那之后学会成为一个近乎专业的程序员。我们刚刚学习了一下怎么在前端显示那些代码的行为,于是我们还需要Javascript。 191 | -------------------------------------------------------------------------------- /src/5.0.android.md: -------------------------------------------------------------------------------- 1 | #Android简单示例 2 | 3 | 由于在某些嵌入式系统中使用的是Android系统,这里给出一个简单的Android App的示例,具体代码可以从clone自[https://github.com/phodal/iot-android](https://github.com/phodal/iot-android) 4 | 5 | 代码说明,经过测试的版本有 6 | 7 | - Android 2.3 8 | - Android 4.0.4 9 | 10 | 机型有 11 | 12 | - HTC G1 (android 2.3) 13 | - Motor xt300 (android 2.3) 14 | - Sony ST25I (android 4.0.4) 15 | - MI2 16 | 17 | 应该可以在大部分的手机上工作。 18 | 19 | ##调用Web Services GET 20 | 21 | 这里我们参考一篇文章来调用Web Services——[Calling Web Services in Android using HttpClient](http://lukencode.com/2010/04/27/calling-web-services-in-android-using-httpclient/) 22 | 23 | ###创建RESTClient 24 | 25 | 在这里我们首先会定义四个REST方法GET、POST、PUT、DELETE 26 | 27 | ```java 28 | public void Execute(RequestMethod method) throws Exception { 29 | switch (method) { 30 | case GET: { 31 | // add parameters 32 | String combinedParams = ""; 33 | if (!params.isEmpty()) { 34 | combinedParams += "?"; 35 | for (NameValuePair p : params) { 36 | String paramString = p.getName() + "=" 37 | + URLEncoder.encode(p.getValue(), HTTP.UTF_8); 38 | if (combinedParams.length() > 1) { 39 | combinedParams += "&" + paramString; 40 | } else { 41 | combinedParams += paramString; 42 | } 43 | } 44 | } 45 | 46 | HttpGet request = new HttpGet(url + combinedParams); 47 | request.addHeader("Accept-Encoding", "gzip"); 48 | 49 | // add headers 50 | for (NameValuePair h : headers) { 51 | request.addHeader(h.getName(), h.getValue()); 52 | } 53 | 54 | executeRequest(request, url); 55 | break; 56 | } 57 | case POST: { 58 | HttpPost request = new HttpPost(url); 59 | request.addHeader("Accept-Encoding", "gzip"); 60 | 61 | // add headers 62 | for (NameValuePair h : headers) { 63 | request.addHeader(h.getName(), h.getValue()); 64 | } 65 | if (!data.equals("")) { 66 | request.setEntity(new StringEntity(data, HTTP.UTF_8)); 67 | } 68 | 69 | if (!params.isEmpty()) { 70 | request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); 71 | } 72 | 73 | executeRequest(request, url); 74 | break; 75 | } 76 | case PUT: { 77 | HttpPut request = new HttpPut(url); 78 | request.addHeader("Accept-Encoding", "gzip"); 79 | 80 | // add headers 81 | for (NameValuePair h : headers) { 82 | request.addHeader(h.getName(), h.getValue()); 83 | } 84 | if (!data.equals("")) { 85 | request.setEntity(new StringEntity(data, HTTP.UTF_8)); 86 | } 87 | 88 | if (!params.isEmpty()) { 89 | request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); 90 | } 91 | 92 | executeRequest(request, url); 93 | break; 94 | } 95 | case DELETE: { 96 | HttpDelete request = new HttpDelete(url); 97 | request.addHeader("Accept-Encoding", "gzip"); 98 | 99 | // add headers 100 | for (NameValuePair h : headers) { 101 | request.addHeader(h.getName(), h.getValue()); 102 | } 103 | 104 | executeRequest(request, url); 105 | break; 106 | } 107 | } 108 | } 109 | ``` 110 | 111 | 这四个方法最后都执行executeRequest来获取响应结果。 112 | 113 | ```java 114 | protected void executeRequest(HttpUriRequest request, String url) { 115 | 116 | HttpParams httpParameters = new BasicHttpParams(); 117 | HttpConnectionParams.setConnectionTimeout(httpParameters, 118 | timeoutConnection); 119 | HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); 120 | 121 | HttpProtocolParams.setUseExpectContinue(httpParameters, false); 122 | request.setParams(httpParameters); 123 | 124 | setOauth(request); 125 | 126 | DefaultHttpClient client = new DefaultHttpClient(); 127 | 128 | HttpResponse httpResponse; 129 | 130 | try { 131 | httpResponse = client.execute(request); 132 | responseCode = httpResponse.getStatusLine().getStatusCode(); 133 | message = httpResponse.getStatusLine().getReasonPhrase(); 134 | 135 | HttpEntity entity = httpResponse.getEntity(); 136 | 137 | if (entity != null) { 138 | InputStream instream = httpResponse.getEntity().getContent(); 139 | Header contentEncoding = httpResponse 140 | .getFirstHeader("Content-Encoding"); 141 | 142 | if (contentEncoding != null 143 | && contentEncoding.getValue().equalsIgnoreCase("gzip")) { 144 | instream = new GZIPInputStream(instream); 145 | } 146 | 147 | // instream = entity.getContent(); 148 | response = convertStreamToString(instream); 149 | 150 | // Closing the input stream will trigger connection release 151 | instream.close(); 152 | } 153 | 154 | } catch (ClientProtocolException e) { 155 | client.getConnectionManager().shutdown(); 156 | e.printStackTrace(); 157 | } catch (IOException e) { 158 | client.getConnectionManager().shutdown(); 159 | e.printStackTrace(); 160 | } 161 | } 162 | ``` 163 | 164 | 接着,我们便可以执行getResponse()函数来获取结果。 165 | 166 | ##使用REST Client获取结果 167 | 168 | 使用RESTClient时,便可以用下面的示例 169 | 170 | 171 | ```java 172 | RestClient client = new RestClient(tUrl); 173 | try { 174 | client.Execute(RequestMethod.GET); 175 | if (client.getResponseCode() != 200) { 176 | //do something 177 | } 178 | //JSONArray jArray = new JSONArray(client.getResponse()); 179 | } catch (Exception e) { 180 | //do something 181 | } 182 | ``` 183 | 184 | 而这时,我们只需要对相应的数据进行处理就可以了,如 185 | 186 | ```java 187 | JSONArray jArray = new JSONArray(client.getResponse()); 188 | JSONObject jObj=jArray.getJSONObject(0); 189 | vshow.setText(jObj.toString()); 190 | 191 | outputJSON(jObj); 192 | ``` 193 | 194 | 将他转换为String,接着在Android端上显示最后的结果。 195 | 196 | -------------------------------------------------------------------------------- /src/1.3.anywhere-css.md: -------------------------------------------------------------------------------- 1 | #无处不在的CSS# 2 | 3 | 或许你觉得CSS一点儿也不重要,而事实上,如果说HTML是建筑的框架,CSS就是房子的装修。那么Javascript呢,我听到的最有趣的说法是小三——还是先让我们回到代码上来吧。 4 | 5 | ##CSS## 6 | 7 | 下面就是我们之前说到的代码,css将Red三个字母变成了红色。 8 | 9 | ```HTML 10 | 11 | 12 | 13 | 14 | 15 |

Red

16 | 17 | 18 | 19 | ``` 20 | 21 | 只是, 22 | 23 | ``` javascript 24 | var para=document.getElementById("para"); 25 | para.style.color="blue"; 26 | ``` 27 | 28 | 将字体变成了蓝色,CSS+HTML让页面有序的工作着,但是Javascript却打乱了这些秩序,有着唯恐世界不乱的精彩,也难怪被冠以小三之名了——或许终于可以理解,为什么以前人们对于Javascript没有好感了——不过这里要讲的是正室,也就是CSS,这时还没有Javascript。 29 | 30 | ![Red Fonts](./images/redfonts.png) 31 | 32 | ##关于CSS## 33 | 34 | 这不是一篇专业讲述CSS的书籍,所以我不会去说CSS是怎么来的,有些东西我们既然可以很容易从其他地方知道,也就不需要花太多时间去重复。诸如重构等这些的目的之一也在于去除重复的代码,不过有些重复是不可少的,也是有必要的,而通常这些东西可能是由其他地方复制过来的。 35 | 36 | 到目前为止我们没有依赖于任何特殊的硬件或者是软件,对于我们来说我们最基本的需求就是一台电脑,或者可以是你的平板电脑,当然也可以是你的智能手机,因为他们都有个浏览器,而这些都是能用的,对于我们的CSS来说也不会有例外的。 37 | 38 | CSS(Cascading Style Sheets),到今天我也没有记得他的全称,CSS还有一个中文名字是层叠式样式表,事实上翻译成什么可能并不是我们关心的内容,我们需要关心的是他能做些什么。作为三剑客之一,它的主要目的在于可以让我们方便灵活地去控制Web页面的外观表现。我们可以用它做出像淘宝一样复杂的界面,也可以像我们的书本一样简单,不过如果要和我们书本一样简单的话,可能不需要用到CSS。HTML一开始就是依照报纸的格式而设计的,我们还可以继续用上面说到的编辑器,又或者是其他的。如果你喜欢DreamWeaver那也不错,不过一开始使用IDE可无助于我们写出良好的代码。 39 | 40 | 忘说了,CSS也是有版本的,和windows,Linux内核等等一样,但是更新可能没有那么频繁,HTML也是有版本的,JS也是有版本的,复杂的东西不是当前考虑的内容。 41 | 42 | ##代码结构## 43 | 44 | 对于我们的上面的Red示例来说,如果没有一个好的结构,那么以后可能就是这样子。 45 | 46 | ```HTML 47 | 48 | 49 | 50 | 51 | 52 |

如果没有一个好的结构

53 |

那么以后可能就是这样子。。。。

54 | 55 | 56 | ``` 57 | 58 | 虽然我们看到的还是一样的: 59 | 60 | ![No Style](./images/nostyle.png) 61 | 62 | 于是我们就按各种书上的建议重新写了上面的代码 63 | 64 | ```HTML 65 | 66 | 67 | 68 | CSS example 69 | 83 | 84 | 85 |

如果没有一个好的结构

86 |

那么以后可能就是这样子。。。。

87 | 88 | 89 | ``` 90 | 91 | 总算比上面好看也好理解多了,这只是临时的用法,当文件太大的时候,正式一点的写法应该如下所示: 92 | 93 | ```HTML 94 | 95 | 96 | 97 | CSS example 98 | 99 | 100 | 101 |

如果没有一个好的结构

102 |

那么以后可能就是这样子。。。。

103 | 104 | 105 | ``` 106 | 107 | 我们需要 108 | 109 | ```HTML 110 | 111 | 112 | 113 | CSS example 114 | 115 | 116 | 117 |

如果没有一个好的结构

118 |

那么以后可能就是这样子。。。。

119 | 120 | 121 | ``` 122 | 123 | 然后我们有一个像app.js一样的style.css放在同目录下,而他的内容便是 124 | 125 | ```CSS 126 | .para{ 127 | font-size: 22px; 128 | color:#f00; 129 | text-align: center; 130 | padding-left: 20px; 131 | } 132 | .para2{ 133 | font-size:44px; 134 | color:#3ed; 135 | text-indent: 2em; 136 | padding-left: 2em; 137 | } 138 | ``` 139 | 140 | 这代码和JS的代码有如此多的相似 141 | 142 | ```javascript 143 | var para={ 144 | font_size:'22px', 145 | color:'#f00', 146 | text_align:'center', 147 | padding_left:'20px', 148 | } 149 | ``` 150 | 151 | 而22px、20px以及#f00都是数值,因此: 152 | 153 | ```javascript 154 | var para={ 155 | font_size:22px, 156 | color:#f00, 157 | text_align:center, 158 | padding_left:20px, 159 | } 160 | ``` 161 | 162 | 目测差距已经尽可能的小了,至于这些话题会在以后讨论到,如果要让我们的编译器更正确的工作,那么我们就需要非常多这样的符号,除非你乐意去理解: 163 | 164 | ```lisp 165 | (dotimes (i 4) (print i)) 166 | ``` 167 | 168 | 总的来说我们减少了符号的使用,但是用lisp便带入了更多的括号,不过这是一种简洁的表达方式,也许我们可以在其他语言中看到。 169 | 170 | ```regex 171 | \d{2}/[A-Z][a-z][a-z]/\d{4} 172 | ``` 173 | 174 | 上面的代码,是为了从一堆数据中找出“某日/某月/某年”。如果一开始不理解那是正则表达式,就会觉得那个很复杂。 175 | 176 | 这门语言可能是为设计师而设计的,但是设计师大部分还是不懂编程的,不过相对来说这门语言还是比其他语言简单易懂一些。 177 | 178 | ##样式与目标## 179 | 如下所示,就是我们的样式 180 | 181 | ```css 182 | .para{ 183 | font-size: 22px; 184 | color:#f00; 185 | text-align: center; 186 | padding-left: 20px; 187 | } 188 | ``` 189 | 190 | 我们的目标就是 191 | 192 | 如果没有一个好的结构 193 | 194 | 所以样式和目标在这里牵手了,问题是他们是如何在一起的呢?下面就是CSS与HTML沟通的重点所在了: 195 | 196 | ###选择器### 197 | 我们用到的选择器叫做类选择器,也就是class,或者说应该称之为class选择器更合适。与类选择器最常一起出现的是ID选择器,不过这个适用于比较高级的场合,诸如用JS控制DOM的时候就需要用到ID选择器。而基本的选择器就是如下面的例子: 198 | 199 | p.para{ 200 | color:#f0f; 201 | } 202 | 203 | 将代码添加到style.css的最下面会发现“如果没有一个好的结构”变成了粉红色,当然我们还会有这样的写法 204 | 205 | p>.para{ 206 | color:#f0f; 207 | } 208 | 209 | 为了产生上面的特殊的样式,虽然不好看,但是我们终于理解什么叫层叠样式了,下面的代码的重要度比上面高,也因此有更高的优先规则。 210 | 211 | 而通常我们可以通过一个 212 | 213 | p{ 214 | text-align:left; 215 | } 216 | 217 | 这样的元素选择器来给予所有的p元素一个左对齐。 218 | 219 | 还有复杂一点的复合型选择器,下面的是HTML文件 220 | 221 | 222 | 223 | 224 | CSS example 225 | 226 | 227 | 228 |

如果没有一个好的结构

229 |
230 |

那么以后可能就是这样子。。。。

231 |
232 | 233 | 234 | 235 | 还有CSS文件 236 | 237 | 238 | .para{ 239 | font-size: 22px; 240 | color:#f00; 241 | text-align: center; 242 | padding-left: 20px; 243 | } 244 | .para2{ 245 | font-size:44px; 246 | color:#3ed; 247 | text-indent: 2em; 248 | padding-left: 2em; 249 | } 250 | 251 | p.para{ 252 | color:#f0f; 253 | } 254 | div#content p { 255 | font-size:22px; 256 | } 257 | 258 | ##更有趣的CSS## 259 | 一个包含了para2以及para_bg的例子 260 | 261 |
262 |

那么以后可能就是这样子。。。。

263 |
264 | 265 | 我们只是添加了一个黑色的背景 266 | 267 | .para_bg{ 268 | background-color:#000; 269 | } 270 | 271 | 重新改变后的网页变得比原来有趣了很多,所谓的继承与合并就是上面的例子。 272 | 273 | 我们还可以用CSS3做出更多有趣的效果,而这些并不在我们的讨论范围里面,因为我们讨论的是be a geek。 274 | 275 | 或许我们写的代码都是那么的简单,从HTML到Javascript,还有现在的CSS,只是总有一些核心的东西,而不是去考虑那些基础语法,基础的东西我们可以在实践的过程中一一发现。但是我们可能发现不了,或者在平时的使用中考虑不到一些有趣的用法或者说特殊的用法,这时候可以通过观察一些精致设计的代码中学习到。复杂的东西可以变得很简单,简单的东西也可以变得很复杂。 276 | 277 | -------------------------------------------------------------------------------- /src/2.1.http.md: -------------------------------------------------------------------------------- 1 | #HTTP 熟悉&陌生 2 | 3 | ##你所没有深入的HTTP 4 | 5 | Internet有两个核心协议: IP和TCP,这样讲述起来似乎会很漫长。 6 | 7 | 基本概念 8 | 9 | > 超文本传输协议 (HTTP-Hypertext transfer protocol) 是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。 10 | 11 | - HTTP是用于客户端与服务端之间的通信。 12 | - 传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的。 13 | 14 | 15 | ``注意``: HTTP协议只规定了客户端与服务端的通信规则,而没有规定其通讯协议,只是现在的大部分实现都是将TCP作为通讯协议。 16 | 17 | ###打开网页时发生了什么 18 | 19 | 简单地来说,当我们在浏览器上输入URL的敲下回车的时候。 20 | 21 | - 浏览器需要查找域名[^domain]的IP,从不同的缓存直至DNS服务器。 22 | - 浏览器会给web服务器发送一个HTTP请求 23 | - 服务器“处理”请求 24 | - 服务器发回一个HTML响应 25 | - 浏览器渲染HTML到页面。 26 | 27 | 在[StackOverflow](http://stackoverflow.com/questions/2092527/what-happens-when-you-type-in-a-url-in-browser)上有一个这样的回答会比较详细。 28 | 29 | - browser checks cache; if requested object is in cache and is fresh, skip to #9 30 | - browser asks OS for server's IP address 31 | - OS makes a DNS lookup and replies the IP address to the browser 32 | - browser opens a TCP connection to server (this step is much more complex with HTTPS) 33 | - browser sends the HTTP request through TCP connection 34 | - browser receives HTTP response and may close the TCP connection, or reuse it for another request 35 | - browser checks if the response is a redirect (3xx result status codes), authorization request (401), error (4xx and 5xx), etc.; these are handled differently from normal responses (2xx) 36 | - if cacheable, response is stored in cache 37 | - browser decodes response (e.g. if it's gzipped) 38 | - browser determines what to do with response (e.g. is it a HTML page, is it an image, is it a sound clip?) 39 | - browser renders response, or offers a download dialog for unrecognized types 40 | 41 | 忽略一些细节便剩下了 42 | 43 | 1. 从浏览器输入URL 44 | 2. 浏览器找到服务器,服务器返回HTML文档 45 | 3. 从对应的服务器下载资源 46 | 47 | 说说第一步,开始时我们输入的是URI(统一资源标识符,Uniform Resource Identifier),它还有另外一个名字叫统一资源定位器(URL[^URL],Uniform Resource Locator)。 48 | 49 | ###URL组成 50 | 51 | 网址算是URL的一个俗称,让我们来看看一个URL的组成,以HTTP版IOT中的URL为例。 52 | 53 | ``http://b.phodal.com/athome/1`` 54 | 55 | 开始之前,我们需要标出URL的80端口以及json文件的全称,那么上面的网址就会变成 56 | 57 | ``http://b.phodal.com:80/athome/1.json`` 58 | 59 | 那么对于这个URL的就有下面几部分组成 60 | 61 | - ``http://`` http说的是这个URL用的是HTTP协议,至于``//``是一个分隔符,用法和C语言中的``;``一样。这样的协议还可以是coap,https,ftp等等。 62 | - ``b`` 是子域名,一个域名在**允许**的情况下可以有不限数量的子域名。 63 | - ``phodal.com`` 代表了一个URL是phodal.com下面的域名 64 | - ``80`` 80是指80端口,默认的都是80,对于一个不是80端口的URL应该是这样的``http://iot-coap.phodal.com:8896/`` 65 | - ``athome`` 指的是虚拟目录部分,或者文件路径 66 | - ``1.json``看上去就是一个文件名,然而也代表着这是一个资源。 67 | 68 | 对就一个稍微复杂点的例子就是 69 | 70 | ``http://ebook.designiot.cn/#你所没有深入的http`` 71 | 72 | 这里的``#``后面是锚部分,如果你打开这个URL就会发现会直接跳转到相应的锚部分,对就于下面这样的一个例子来说 73 | 74 | ``http://www.phodal.com/search/?q=iot&type=blog`` 75 | 76 | ``?``后面的``q=iot&type=blog``的部分是参数部分,通常用于查询或者、搜索。 77 | 78 | ##一次HTTP GET请求 79 | 80 | 当我们打开最小物联网系统的一个页面时,如[http://b.phodal.com/athome/1.json](http://b.phodal.com/athome/1.json) 81 | 82 | 我们在浏览器上看到的结果是 83 | 84 | ```javascript 85 | [ 86 | { 87 | "id": 1, 88 | "temperature": 19, 89 | "sensors1": 31, 90 | "sensors2": 7.5, 91 | "led1": 0 92 | } 93 | ] 94 | ``` 95 | 96 | 只是我们看到的是结果,忽略了这其中的过程,于是我们用curl[^curl]命令来看看详细的情况。 97 | 98 | ```bash 99 | curl -I -s http://b.phodal.com/athome/1.json 100 | ``` 101 | 102 | 出于某种原因考虑,删去了其中一些元素,剩下下面这些。 103 | 104 | ```bash 105 | HTTP/1.1 200 OK 106 | Content-Type: application/json 107 | Date: Fri, 05 Sep 2014 15:05:49 GMT 108 | 109 | [{"id":1,"temperature":19,"sensors1":31,"sensors2":7.5,"led1":0}] 110 | ``` 111 | 112 | 我们用curl命令向服务器发起了GET请求,服务器返回了上面的结果。 113 | 114 | ###HTTP响应 115 | 116 | 一个HTTP响应由三部分组成 117 | 118 | - 状态行(状态码) 119 | - 消息报头(响应报头) 120 | - 响应正文(消息体) 121 | 122 | ####HTTP响应 状态码 123 | 124 | 在上面的结果中,状态行是 125 | 126 | ```bash 127 | HTTP/1.1 200 OK 128 | ``` 129 | 130 | 返回的状态码是200,OK是状态码的原因短语。 131 | 132 | 如果是一个跳转的页面,它就可能是下面的结果: 133 | 134 | ```bash 135 | HTTP/1.0 301 MOVED PERMANENTLY 136 | Date: Mon, 08 Sep 2014 12:04:01 GMT 137 | Content-Type: text/html; charset=utf-8 138 | ``` 139 | 140 | HTTP Status有五种状态,而这五种状态又有所细分,提一下这五种状态,详细可参见[http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81](http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81) 141 | 142 | - 1xx消息 143 | - 2xx成功 144 | - 3xx重定向 145 | - 4xx客户端错误 146 | - 5xx服务器错误 147 | 148 | 149 | 如 150 | 151 | - 200 ok - 成功返回状态,对应,GET,PUT,PATCH,DELETE. 152 | - 201 created - 成功创建。 153 | - 304 not modified - HTTP缓存有效。 154 | - 400 bad request - 请求格式错误。 155 | - 401 unauthorized - 未授权。 156 | - 403 forbidden - 鉴权成功,但是该用户没有权限。 157 | - 404 not found - 请求的资源不存在 158 | - 405 method not allowed - 该http方法不被允许。 159 | - 410 gone - 这个url对应的资源现在不可用。 160 | - 415 unsupported media type - 请求类型错误。 161 | - 422 unprocessable entity - 校验错误时用。 162 | - 429 too many request - 请求过多。 163 | 164 | ####HTTP响应 响应报头 165 | 166 | 在这次响应中,返回了两个报头,即 167 | 168 | ```bash 169 | Content-Type: application/json 170 | Date: Fri, 05 Sep 2014 15:05:49 GMT 171 | ``` 172 | 173 | Content-Type和Date,在这里的Context-Type是application/json,而通常情况下我们打开一个网站时,他的Content-Type应该是text/html。 174 | 175 | ```bash 176 | Content-Type: text/html; 177 | ``` 178 | 179 | Content-Type是最重要的报头。 180 | 181 | ####HTTP响应 响应正文 182 | 183 | 正文才是我们真正想要的内容,上面的都是写给浏览器看的,一般的人不会去关注这些。 184 | 185 | ```javascript 186 | HTTP/1.1 200 OK 187 | Server: phodal.com/0.17.5 188 | Content-Type: application/json 189 | 190 | [{"id":1,"temperature":19,"sensors1":31,"sensors2":7.5,"led1":0}] 191 | ``` 192 | 193 | 通常这是以某种格式写的,在这里是以JSON写的,而对于一个网站的时候则是HTML,如: 194 | 195 | ```html 196 | 197 | 198 | 199 | Document 200 | 201 | 202 | 203 | 204 | 205 | ``` 206 | 207 | 那么这次GET请求返回的就是: 208 | 209 | ```bash 210 | HTTP/1.0 200 OK 211 | Date: Mon, 08 Sep 2014 12:04:01 GMT 212 | Content-Type: text/html; charset=utf-8 213 | 214 | 215 | 216 | 217 | Document 218 | 219 | 220 | [{"id":1,"temperature":19,"sensors1":31,"sensors2":7.5,"led1":0}] 221 | 222 | 223 | ``` 224 | 225 | 虽然与第一次请求的结果在游览器上看似乎是一样的(ps:可能有微小的差异),然而其本质是不同的。 226 | 227 | 推荐及参考书目: 228 | 229 | - 《Web性能权威指南》 230 | - 《图解HTTP》 231 | - 《RESTful Web Services Cookbook》 232 | - 《RESTful Web APIs》 233 | 234 | [^domain]:形如http://www.phodal.com 235 | 236 | [^URL]: URL 是 URI 的子集 237 | 238 | [^curl]: curl是利用URL语法在命令行方式下工作的开源文件传输工具。 239 | -------------------------------------------------------------------------------- /src/1.4.anywhere-hjc.md: -------------------------------------------------------------------------------- 1 | # 无处不在的三剑客# 2 | 3 | 这时我们终于了解了我们的三剑客,他们也就这么可以结合到一起了,HTML+Javascript+CSS是这一切的基础。而我们用到的其他语言如PHP、Python、Ruby等等到最后都会变成上面的结果,当然还有Coffeescript之类的语言都是以此为基础,这才是我们需要的知识。 4 | 5 | ##Hello,Geek## 6 | 有了一些些基础之后,我们终于能试着去写一些程序了。也是时候去创建一个像样的东西,或许你在一些界面设计方面的书籍看过类似的东西,可能我写得也没有那些内容好,只是这些都是一些过程。过去我们都是一点点慢慢过来的,只是现在我们也是如此,技术上的一些东西,事实上大家都是知道的。就好比我们都觉得我们可以开个超市,但是如果让我们去开超市的话,我们并不一定能赚钱。 7 | 8 | 学习编程的目的可能不在于我们能找到一份工作,那只是在编程之外的东西,虽然确实也是很确定的。但是除此之处,有些东西也是很重要的。 9 | 10 | 过去总是不理解为什么会一些人会不厌其烦地去回答别人的问题,有时候可能会想是一种能力越大责任越大的感觉,但是有时候在写一些博客或者回答别人的问题的时候我们又重新思考了这些问题,又重新学习了这些技能。所以这里可能说的不是关于编程的东西而是一些编程以外的东西,关于学习或者学习以外的东西。 11 | 12 | ##从源码学习## 13 | 过去总觉得学了一种语言的语法便算是学会了一种语言,直到有一天接触运用该语言的项目的时候,虽然也会写上几行代码,但是却不像这种语言的风格。于是这也是这一篇的意义所在了: 14 | 15 | ##浏览器渲染过程 16 | 17 | 基本的渲染引擎的过程如下图所示: 18 | 19 | ![flow](./images/flow.png) 20 | 21 | - 解析HTML去构建DOM树 22 | - 渲染树形结构 23 | - 生成渲染的树形图布局 24 | - 绘制树形图 25 | 26 | 对于Webkit浏览器来说,他的过程如下所示: 27 | 28 | ![webkitflow](./images/webkitflow.png) 29 | 30 | ###HTML### 31 | 写好HTML的一个要点在于读别人写的代码,这只是一方面,我们所说的HTML方面的内容可能不够多,原因有很多,很多东西都需要在实战中去解决。读万卷书和行万里路,分不清哪个有重要的意义,但是如果可以同时做好两个的话,成长会更快的。 32 | 33 | 写好HTML应该会有下面的要点 34 | 35 | - 了解标准及遵守绝大多数标准 36 | - 注重可读性,从ID及CLASS的命名 37 | - 关注SEO与代码的联系 38 | 39 | 或许在这方面我也算不上很了解,不过按笔者的经验来说,大致就是如此。 40 | 41 | 多数情况下我们的HTML是类似于下面这样子的 42 | 43 | ```html 44 |
45 | {% nevercache %} 46 | {% include "includes/user_panel.html" %} 47 | {% endnevercache %} 48 |
49 |
50 | {% block right_panel %} 51 | {% ifinstalled mezzanine.twitter %} 52 | {% include "twitter/tweets.html" %} 53 | {% endifinstalled %} 54 | {% endblock %} 55 |
56 |
57 |
58 | ``` 59 | 60 | 换句话说HTML只是基础,而不是日常用到的。我们的HTML是由template生成的,我们可以借助于mustache.js又或者是angluarjs之类的js库来生成最后的HTML,所以这里只是一个开始。 61 | 62 | 还需要了解的一部分就是HTML的另外一个重要的部分,DOM树形结构 63 | 64 | 65 | ##DOM树形结构图## 66 | 67 | > DOM是文档对象化模型(Document Object Model)的简称。DOM Tree是指通过DOM将HTML页面进行解析,并生成的HTML tree树状结构和对应访问方法。 68 | 69 | ![DOM Tree](./images/dom_tree.jpg) 70 | 71 | ###javascript### 72 | 这里以未压缩的jQuery源码和zepto.js作一个小小的比较,zepto.js是兼容jQuery的,因此我们举几个有意思的函数作一简单的比较,关于源码可以在官网上下载到。 73 | 74 | 在zepto.js下面判断一个值是否是函数的方面如下, 75 | 76 | ```javascript 77 | function isFunction(value) { return type(value) == "function" } 78 | ``` 79 | 80 | 而在jQuery下面则是这样的 81 | 82 | ```javascript 83 | isFunction: function( obj ) { 84 | return jQuery.type(obj) === "function"; 85 | } 86 | ``` 87 | 88 | 而他们的用法是一样的,都是 89 | 90 | ```javascript 91 | $.isFunction(); 92 | ``` 93 | 94 | jQuery的作法是将诸如isFunction,isArray这些函数打包到jQuery.extend中,而zepto.js的也是这样的,只不过多了一行 95 | 96 | ```javascript 97 | $.isFunction = isFunction 98 | ``` 99 | 遗憾的是我也没去了解过为什么,之前我也没有看过这些库的代码,所以这个问题就要交给读者去解决了。jQuery里面提供了函数式编程接口,不过jQuery更多的是构建于CSS选择器之上,对于DOM的操作比javascript自身提供的功能强大得多。如果我们的目的在于更好的编程,那么可能需要诸如Underscore.js之类的库。或许说打包自己常用的函数功能为一个库,诸如jQuery 100 | 101 | ```javascript 102 | function isFunction(value) { return type(value) == "function" } 103 | function isWindow(obj) { return obj != null && obj == obj.window } 104 | function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } 105 | function isObject(obj) { return type(obj) == "object" } 106 | ``` 107 | 108 | 我们需要去了解一些故事背后的原因,越来越害怕GUI的原因之一,在于不知道背后发生了什么,即使是开源的,我们也无法了解真正的背后发生什么了。对于不是这个工具、软件的用户来说,开源更多的意义可能在于我们可以添加新的功能,当然还有免费。如果没有所谓的危机感,以及认为自己一直在学习工具的话,可以试着去打包自己的函数,打包自己的库。 109 | 110 | ```javascript 111 | var calc={ 112 | add: function(a,b){ 113 | return a+b; 114 | }, 115 | sub: function(a,b){ 116 | return a-b; 117 | }, 118 | dif: function(a,b){ 119 | if(a>b){ 120 | return a; 121 | }else{ 122 | return b; 123 | } 124 | } 125 | } 126 | ``` 127 | 128 | 然后用诸如jslint测试一下代码。 129 | 130 | ```bash 131 | $ ./jsl -conf jsl.default.conf 132 | JavaScript Lint 0.3.0 (JavaScript-C 1.5 2004-09-24) 133 | Developed by Matthias Miller (http://www.JavaScriptLint.com) 134 | 135 | app.js 136 | /Users/fdhuang/beageek/chapter4/src/app.js(15): lint warning: missing semicolon 137 | } 138 | ........^ 139 | 140 | 141 | 0 error(s), 1 warning(s) 142 | ``` 143 | 144 | 于是我们需要在第15行添加一个分号。 145 | 146 | 最好的方法还是阅读别人的代码,而所谓的别人指的是一些相对较大的网站的,有比较完善的开发流程,代码质量也不会太差。而所谓的复杂的代码都是一步步构建上去的,罗马不是一天建成的。 147 | 148 | 有意思的是多数情况下,我们可能会用原型去开发我们的应用,而这也是我们需要去了解和掌握的地方, 149 | 150 | ```javascript 151 | function Calc(){ 152 | 153 | } 154 | Calc.prototype.add=function(a,b){ 155 | return a+b; 156 | }; 157 | Calc.prototype.sub=function(a,b){ 158 | return a-b; 159 | }; 160 | ``` 161 | 162 | 我们似乎在这里展示了更多的Javascript的用法,但是这不是一好的关于Javascript的介绍,有一天我们还要用诸如qunit之类的工具去为我们的function写测试,这时就是一个更好的开始。 163 | 164 | 如果我们乐意的话,我们也可以构建一个类似于jQuery的框架,以用来学习。 165 | 166 | 作为一门编程语言来说,我们学得很普通,在某种意义上来说算不上是一种入门。但是如果我们可以在其他的好书在看到的内容,就没有必要在这里进行复述,目的在于一种学习习惯的养成。 167 | 168 | ###CSS### 169 | 170 | CSS有时候很有趣,但是有时候有很多我们没有意识到的用法,这里以Bootstrap为例,这是一个不错的CSS库。最令人兴奋的是没有闭源的CSS,没有闭源的JS,这也就是前端好学习的地方所在了,不过这是一个开源的CSS库,虽然是这样叫的,但是称之为CSS库显然不合适。 171 | 172 | ```css 173 | a, 174 | a:visited { 175 | text-decoration: underline; 176 | } 177 | a[href]:after { 178 | content: " (" attr(href) ")"; 179 | } 180 | abbr[title]:after { 181 | content: " (" attr(title) ")"; 182 | } 183 | a[href^="javascript:"]:after, 184 | a[href^="#"]:after { 185 | content: ""; 186 | } 187 | ``` 188 | 189 | 这里有一些有趣的,值得一讲的CSS用法。 190 | 191 | - 伪类选择器,如a:visited这样需要其他条件来对元素应用样式,用于已访问的链接。 192 | - 属性选择器,如a[href]这样当a元素存在href这样的属性的时候来寻找应用元素。 193 | 194 | 其他的还需要去好好了解的就是**CSS的盒模型**,作为CSS的基石之一。 195 | 196 | ##CSS盒模型图 197 | 198 | (ps:以下内容来自于Mozilla Developer NetWorks) 199 | 200 | CSS下这些矩形盒子由标准盒模型描述。这个模型描述元素内容占用空间。盒子有四个边界:外边距边界margin edge, 边框边界border edge, 内边距边界padding edge 与 内容边界content edge。 201 | 202 | ![CSS Box Model](./images/box-model.gif) 203 | 204 | 205 | 内容区域content area 是真正包含元素内容的区域。位于内容边界的内部,它的大小为内容宽度 或 content-box宽及内容高度或content-box高。 206 | 207 | 如果 box-sizing 为默认值, width, min-width, max-width, height, min-height 与 max-height 控制内容大小。 208 | 209 | 内边距区域padding area 用内容及可能的边框之间的空白区域扩展内容区域。它位于内边距边界内部,通常有背景——颜色或图片(不透明图片盖住背景颜色). 它的大小为 padding-box 宽与 padding-box 高。 210 | 211 | 内边距与内容边界之间的空间可以由 padding-top, padding-right, padding-bottom, padding-left 和简写属性 padding 控制。 212 | 213 | 边框区域border area 是包含边框的区域,扩展了内边距区域。它位于边框边界内部,大小为 border-box 宽和 border-box 高。由 border-width 及简写属性 border控制。 214 | 215 | 外边距区域margin area用空白区域扩展边框区域,以分开相邻的元素。它的大小为 margin-box 的高宽。 216 | 217 | 外边距区域大小由 margin-top, margin-right, margin-bottom, margin-left 及简写属性 margin 控制。 218 | 219 | 在 外边距合并 的情况下,由于盒之间共享外边距,外边距不容易弄清楚。 220 | 221 | 最后注意,对于行内非替换元素,其占用空间(行高)由 line-height 决定,即使有内边距与边框。 222 | 223 | 诸如 224 | 225 | ```css 226 | * { 227 | margin: 0px; 228 | padding: 0px; 229 | font-family: Helvetica; 230 | } 231 | ``` 232 | 233 | 这样的通用器用来进行全局选择的工具和我们用于抵消某个body对于子选择器的影响一样值得注意得多。 234 | 235 | ##笔记## 236 | 写博客似乎是一个不错的好习惯,作为一个不是很优秀的写手。对于来说,有时候发现原来能教会别人对于自己的能力来说算是一种肯定。有些时候教会别人才算是自己学会的表现,总会在项目上的时候需要自己去复述工作的一个过程,我们需要整理好我们的思路才能带给别人更多的收获。我们的笔记上总会留下自己的学习的一些过程,有些时候我们想要的只是一点点的鼓励,有时是诸如评论一类,有时可能是诸如访问量。更多的可能是我们可以重新整理自己的知识,好好复习一下,以便于好好记住,写出来是一个好的过程。 237 | 238 | 无处不在的三剑客就这样到了这里,写得似乎很多也很少,但是还是没有做出来一个东西,于是我们朝着这样一个方向前进。 239 | -------------------------------------------------------------------------------- /template/template.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper, 11pt]{article} 2 | \usepackage{geometry} % 設定邊界 3 | \geometry{ 4 | top=1in, 5 | inner=1in, 6 | outer=1in, 7 | bottom=1in, 8 | headheight=3ex, 9 | headsep=2ex 10 | } 11 | \usepackage{tabu} 12 | \usepackage[T1]{fontenc} 13 | \usepackage{lmodern} 14 | \usepackage{booktabs} 15 | \usepackage{amssymb,amsmath} 16 | \usepackage{ifxetex,ifluatex} 17 | \usepackage{fixltx2e} % provides \textsubscript 18 | % use upquote if available, for straight quotes in verbatim environments 19 | \IfFileExists{upquote.sty}{\usepackage{upquote}}{} 20 | \ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex 21 | \usepackage[utf8]{inputenc} 22 | $if(euro)$ 23 | \usepackage{eurosym} 24 | $endif$ 25 | \else % if luatex or xelatex 26 | \usepackage{fontspec} % 允許設定字體 27 | \usepackage{xeCJK} % 分開設置中英文字型 28 | \setCJKmainfont{STSong} % 設定中文字型 29 | \setmainfont[Mapping=tex-text]{Times New Roman}%\rmfamily 使用的字体,默认英文和数字的字体。 % 設定英文字型 30 | \setromanfont{Georgia} % 字型 31 | \setmonofont{Courier New} 32 | \linespread{1.2}\selectfont % 行距 33 | \XeTeXlinebreaklocale "zh" % 針對中文自動換行 34 | \XeTeXlinebreakskip = 0pt plus 1pt % 字與字之間加入0pt至1pt的間距,確保左右對整齊 35 | \parindent 0em % 段落縮進 36 | \setlength{\parskip}{20pt} % 段落之間的距離 37 | \ifxetex 38 | \usepackage{xltxtra,xunicode} 39 | \fi 40 | \defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase} 41 | \newcommand{\euro}{€} 42 | $if(mainfont)$ 43 | \setmainfont{$mainfont$} 44 | $endif$ 45 | $if(sansfont)$ 46 | \setsansfont{$sansfont$} 47 | $endif$ 48 | $if(monofont)$ 49 | \setmonofont{$monofont$} 50 | $endif$ 51 | $if(mathfont)$ 52 | \setmathfont{$mathfont$} 53 | $endif$ 54 | \fi 55 | % use microtype if available 56 | \IfFileExists{microtype.sty}{\usepackage{microtype}}{} 57 | $if(geometry)$ 58 | \usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry} 59 | $endif$ 60 | $if(natbib)$ 61 | \usepackage{natbib} 62 | \bibliographystyle{plainnat} 63 | $endif$ 64 | $if(biblatex)$ 65 | \usepackage{biblatex} 66 | $if(biblio-files)$ 67 | \bibliography{$biblio-files$} 68 | $endif$ 69 | $endif$ 70 | $if(listings)$ 71 | \usepackage{listings} 72 | $endif$ 73 | $if(lhs)$ 74 | \lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{} 75 | $endif$ 76 | $if(highlighting-macros)$ 77 | $highlighting-macros$ 78 | $endif$ 79 | $if(verbatim-in-note)$ 80 | \usepackage{fancyvrb} 81 | $endif$ 82 | $if(tables)$ 83 | \usepackage{longtable} 84 | $endif$ 85 | 86 | \usepackage{graphicx} 87 | \usepackage{caption} 88 | % We will generate all images so they have a width \maxwidth. This means 89 | % that they will get their normal width if they fit onto the page, but 90 | % are scaled down if they would overflow the margins. 91 | \makeatletter 92 | \def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth 93 | \else\Gin@nat@width\fi} 94 | \makeatother 95 | \let\Oldincludegraphics\includegraphics 96 | \renewcommand{\includegraphics}[1]{\Oldincludegraphics[width=\maxwidth]{#1}} 97 | \ifxetex 98 | \usepackage[setpagesize=false, % page size defined by xetex 99 | unicode=false, % unicode breaks when used with xetex 100 | xetex]{hyperref} 101 | \else 102 | \usepackage[unicode=true]{hyperref} 103 | \fi 104 | \hypersetup{breaklinks=true, 105 | bookmarks=true, 106 | pdfauthor={$author-meta$}, 107 | pdftitle={$title-meta$}, 108 | colorlinks=true, 109 | urlcolor=$if(urlcolor)$$urlcolor$$else$blue$endif$, 110 | linkcolor=$if(linkcolor)$$linkcolor$$else$magenta$endif$, 111 | pdfborder={0 0 0}} 112 | \urlstyle{same} % don't use monospace font for urls 113 | $if(links-as-notes)$ 114 | % Make links footnotes instead of hotlinks: 115 | \renewcommand{\href}[2]{#2\footnote{\url{#1}}} 116 | $endif$ 117 | $if(strikeout)$ 118 | \usepackage[normalem]{ulem} 119 | % avoid problems with \sout in headers with hyperref: 120 | \pdfstringdefDisableCommands{\renewcommand{\sout}{}} 121 | $endif$ 122 | \setlength{\parindent}{0pt} 123 | %\setlength{\parskip}{6pt plus 2pt minus 1pt} 124 | \setlength{\emergencystretch}{3em} % prevent overfull lines 125 | 126 | \title{\huge 基于REST服务的最小物联网系统设计} % 設置標題,使用巨大字體 127 | \author{Phodal Huang} % 設置作者 128 | \date{February 2014} % 設置日期 129 | \usepackage{titling} 130 | \setlength{\droptitle}{-8em} % 將標題移動至頁面的上面 131 | 132 | \usepackage{fancyhdr} 133 | \usepackage{lastpage} 134 | \pagestyle{fancyplain} 135 | 136 | $if(numbersections)$ 137 | \setcounter{secnumdepth}{5} 138 | $else$ 139 | \setcounter{secnumdepth}{0} 140 | $endif$ 141 | $if(verbatim-in-note)$ 142 | \VerbatimFootnotes % allows verbatim text in footnotes 143 | $endif$ 144 | $if(lang)$ 145 | \ifxetex 146 | \usepackage{polyglossia} 147 | \setmainlanguage{$mainlang$} 148 | \else 149 | \usepackage[$lang$]{babel} 150 | \fi 151 | $endif$ 152 | $for(header-includes)$ 153 | $header-includes$ 154 | $endfor$ 155 | 156 | $if(title)$ 157 | \title{$title$} 158 | $endif$ 159 | \author{$for(author)$$author$$sep$ \and $endfor$} 160 | \date{$date$} 161 | 162 | %%%% 段落首行缩进两个字 %%%% 163 | \makeatletter 164 | \let\@afterindentfalse\@afterindenttrue 165 | \@afterindenttrue 166 | \makeatother 167 | \setlength{\parindent}{2em} %中文缩进两个汉字位 168 | 169 | 170 | %%%% 下面的命令重定义页面边距,使其符合中文刊物习惯 %%%% 171 | \addtolength{\topmargin}{-2pt} 172 | \setlength{\oddsidemargin}{0.63cm} % 3.17cm - 1 inch 173 | \setlength{\evensidemargin}{\oddsidemargin} 174 | \setlength{\textwidth}{14.66cm} 175 | \setlength{\textheight}{24.00cm} % 24.62 176 | 177 | %%%% 下面的命令设置行间距与段落间距 %%%% 178 | \linespread{1.4} 179 | % \setlength{\parskip}{1ex} 180 | \setlength{\parskip}{0.5\baselineskip} 181 | 182 | 183 | \begin{document} 184 | %%%% 定理类环境的定义 %%%% 185 | \newtheorem{example}{例} % 整体编号 186 | \newtheorem{algorithm}{算法} 187 | \newtheorem{theorem}{定理}[section] % 按 section 编号 188 | \newtheorem{definition}{定义} 189 | \newtheorem{axiom}{公理} 190 | \newtheorem{property}{性质} 191 | \newtheorem{proposition}{命题} 192 | \newtheorem{lemma}{引理} 193 | \newtheorem{corollary}{推论} 194 | \newtheorem{remark}{注解} 195 | \newtheorem{condition}{条件} 196 | \newtheorem{conclusion}{结论} 197 | \newtheorem{assumption}{假设} 198 | 199 | %%%% 重定义 %%%% 200 | \renewcommand{\contentsname}{目录} % 将Contents改为目录 201 | \renewcommand{\abstractname}{摘要} % 将Abstract改为摘要 202 | \renewcommand{\refname}{参考文献} % 将References改为参考文献 203 | \renewcommand{\indexname}{索引} 204 | \renewcommand{\figurename}{图} 205 | \renewcommand{\tablename}{表} 206 | \renewcommand{\appendixname}{附录} 207 | 208 | \maketitle 209 | 210 | $for(include-before)$ 211 | $include-before$ 212 | 213 | $endfor$ 214 | $if(toc)$ 215 | { 216 | \newpage 217 | \hypersetup{linkcolor=black} 218 | \setcounter{tocdepth}{$toc-depth$} 219 | \tableofcontents 220 | } 221 | \newpage 222 | $endif$ 223 | $body$ 224 | 225 | $if(natbib)$ 226 | $if(biblio-files)$ 227 | $if(biblio-title)$ 228 | $if(book-class)$ 229 | \renewcommand\bibname{$biblio-title$} 230 | $else$ 231 | \renewcommand\refname{$biblio-title$} 232 | $endif$ 233 | $endif$ 234 | \bibliography{$biblio-files$} 235 | 236 | $endif$ 237 | $endif$ 238 | $if(biblatex)$ 239 | \printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$ 240 | 241 | $endif$ 242 | $for(include-after)$ 243 | $include-after$ 244 | 245 | $endfor$ 246 | \end{document} -------------------------------------------------------------------------------- /src/1.7.python.md: -------------------------------------------------------------------------------- 1 | #Python 代码如散文 2 | 3 | ![python](./images/python.png) 4 | 5 | 作为一门计算机语言来说,Python会有下面的特点。 6 | 7 | - 语言学习起来容易 8 | - 解决生活中的实际问题 9 | - 支持多学科 10 | 11 | 我们可以和其他不是脚本语言的语言进行一个简单的对比,如C,你需要去编译去运行,有时候还需要解决跨平台问题,本来你是在你的Windows上运行得好好的,但是有一天你换了一个Mac电脑的时候,问题变得很棘手,你甚至不知道怎么去解决问题。我没有用过MFC,听说很方便,但是在其他平台下就没有一个好的解决方案。这里可能跑得有点远,但是不同的用户可能在不同的平台上,这也就是脚本语言的优势所在了。 12 | 13 | ##代码与散文## 14 | 你可能听过,也可能了解过,不过在这里我们可能不会去讲述那些基础的语法的东西,我们想说的是代码格式的重要性,在html中你可以这样去写你的代码 15 | 16 | ```html 17 | This is a Title 18 |
19 |

flakjfaklfjalfa

20 | 21 | ``` 22 | 23 | 又或者是js的minify,它可能会使你的代码看起来像是这样的: 24 | 25 | ```javascript 26 | function NolTracker(b,a){this.pvar=b;this.mergeFeatures(a)} 27 | ``` 28 | 29 | 可能的是如果是python的话,你可能会遇到下面的问题。。 30 | 31 | ```bash 32 | File "steps.py", line 10 33 | try: 34 | ^ 35 | IndentationError: expected an indented block 36 | ``` 37 | 38 | 如果你对JSLint、Lint这类的工具有点印象的话,你也可以认为python集成了这类工具。整洁的代码至少应该看上去要有整洁的衣服,就好像是我们看到的一个人一样,而后我们才会有一个好的印象。更主要的一点是代码是写给人看的,而衣服更多的时候对于像我这样的人来说,他首先应该是要保暖的,其次对于一个懒的人来说。。。 39 | 40 |
程序应该是具有可读性的短文,它将在计算机上执行,从而解决某些问题
41 | 42 | 我们需要去读懂别人的代码,别人也需要去读懂我们的代码。计算机可以无条件地执行你那未经编排过的程序,但是人就不是如此了。 43 | 44 | ```javascript 45 | var calc={add: function(a,b){return a+b;},sub: function(a,b){return a-b;},dif: function(a,b){if(a>b){return a;}else{return b;}}} 46 | ``` 47 | 48 | 上面的代码相对于下面的代码可读性没有那么多,但是计算机可以无条件地执行上面的代码。上面的代码对于网络传输来说是好的,但是对于人来说并不是如此,我们需要一些工具来辅助我们去读懂上面的代码。如果代码上写得没有一点可读性,诸如函数命名没有多少实际意义,如果我们把前面的函数就成这样: 49 | 50 | ```javascript 51 | var c={ 52 | a: function(a,b){ 53 | return a+b; 54 | }, 55 | s: function(a,b){ 56 | return a-b; 57 | }, 58 | d: function(a,b){ 59 | if(a>b){ 60 | return a; 61 | }else{ 62 | return b; 63 | } 64 | } 65 | } 66 | ``` 67 | 68 | 那么只有在我们理解了这个函数是干什么之后才能理解函数是干什么,而不是光看函数名就可以了。 69 | 70 | 在Javascript解决一个函数的办法有很多,在其他一些语言如Ruby或者Perl中也是如此,解决问题的办法有很多,对于写代码的人来说是一个享受的过程,但是对于维护的人来说并非如此。而这个和Python的思想不是很一致的是,Python设计的理念是 71 | 72 |
对于特定的问题,只要有一种最好的方法来解决就够了
73 | 74 | 可读性的代码在今天显得比以前重要的多,以前写程序的时候我们需要去考虑使用汇编或者其他工具来提高程序的效率。 75 | 76 | ``` 77 | .global _start 78 | 79 | .text 80 | _start: 81 | # write(1, message, 13) 82 | mov $1, %rax # system call 1 is write 83 | mov $1, %rdi # file handle 1 is stdout 84 | mov $message, %rsi # address of string to output 85 | mov $13, %rdx # number of bytes 86 | syscall # invoke operating system to do the write 87 | 88 | # exit(0) 89 | mov $60, %rax # system call 60 is exit 90 | xor %rdi, %rdi # we want return code 0 91 | syscall # invoke operating system to exit 92 | message: 93 | .ascii "Hello, world\n" 94 | ``` 95 | 96 | 所以上面的代码的可读性在今天新生一代的程序员来说可能没有那么容易理解。芯片运行的速度越来越快,在程序上我们也需要一个越来越快的解决方案,而所谓的越来越快的解决方案指的不是运行速度上,而是开发速度上。如果你没有办法在同样时间内开发出更好的程序,那么你就可能输给你的竞争对手。 97 | 98 | ###开始之前 99 | 100 | 我们终于又从一种语言跳到了另外一种语言,我们可能习惯了一种模式,而不敢于去尝试新的东西,这些或许是我们的一些习惯又或者是因为害怕等等。 101 | 102 | 作为另外一个跨平台能力很强的语言,这里说的是与Javascript、HTML比较,或许你会觉得C算是最好的,但是我们这里讨论更多的是脚本语言,也就是直接可以运行的。在现在主流的大多数移动平台上,python也有良好的支持,如Android,IOS,只是这些算是类Unix系统内核,python还支持之前Nokia的Symbian。 103 | 104 | 开始之前我们需要确认我们的平台上已经有了python环境,也就是可以运行下面的Hello,World,你可以在网上很多地方看到,最简单的地方还是到官网,又或者是所用移动平台的store下载。 105 | 106 | ###Python的Hello,World 107 | 108 | Python的Hello,World有两种形式,作为一种脚本语言来说,Javascript也是一种脚本语言,只是两者之间有太多的不同之处,每个人都会有不同的选择对于一种语言用来作为其的习惯。于是这就是我们的 109 | 110 | print "Hello,World" 111 | 112 | 当我们把我们的脚本在shell环境下运行时 113 | 114 | ```bash 115 | >>> print "Hello,world" 116 | File "", line 1 117 | print "Hello,world" 118 | ^ 119 | IndentationError: unexpected indent 120 | >>> print "Hello,world" 121 | Hello,world 122 | >>> 123 | ``` 124 | 125 | 如果你没有预料到缩进带来的问题的时候,这就是一个问题了。 126 | 127 | 和我们在Javascript或者是CSS里面一样,我们也可以用一个文件的方式来写入我们的代码,文件后缀名是py,所以创建一个helloworld.py,输入上面的代码,然后执行 128 | 129 | python helloworld.py 130 | 131 | 一个理想的结果,或许你试过C语言的helloworld,如果了解过GCC的话应该是可以这样的: 132 | 133 | 134 | ./a.out 135 | 136 | 也就是执行编译完后的程序,需要注意的是helloworld.py没有编译,不过也会输出 137 | 138 | Hello,world 139 | 140 | ###我们想要的Hello,World 141 | 142 | 我们想展示的是如何结合前面学习的内容做一个更有意思的Hello,World。 143 | 144 | ```python 145 | import cherrypy 146 | class HelloWorld(object): 147 | def index(self): 148 | return "Hello World!" 149 | index.exposed = True 150 | 151 | cherrypy.quickstart(HelloWorld()) 152 | ``` 153 | 154 | ##算法## 155 | 156 | 我们需要去了解算法(algorithm),引经据典的话就是这样子: 157 | 158 |
a process or set of rules to be followed in calculations or other problem-solving operations, especially by a computer
159 | 160 | 也就是计算或其他解决问题的操作需要遵循的一个过程或者一套规则,书上还提到的说法是——解决问题的诀窍,让我想起了hack一词。我们总会去想某些东西是否有一个更快的计算方法,有时候在处理某些问题上也显示了一个好的算法的重要性。 161 | 162 | ##实用主义哲学 163 | 164 | (来自于:HyryStudio) 165 | 166 | 大多数工程师、科学家使用科学计算软件的目的都是为了快速解决其工作中遇到的问题,而不是开发出一套完整的软件。这就是为什么MATLAB这样的商用科学计算软件十分流行的原因。而Python在这一点上实际上和MATLAB十分相似,我们也可以使用Python众多的扩展库快速写出一次性的数据处理、运算的脚本。然而由于Python语言的一些高级特性,以及众多的科学计算之外的扩展库,我们可以将积累下来的一次性脚本进行改造,为它们提供命令行、GUI、数据库、网络等众多接口,最终成为一套完整的工具包或者实用的计算软件。而且由于是开源的自由软件,我们可以在任何系统中安装Python环境,运行我们 的程序。 167 | 168 | Python一直保持着很强的实用主义,它通常不会去试着重新开发一整套函数库,而是将现有的开源函数库包装成其扩展库。而Python则通过这些扩展库将众多的开源函数库连接在一起,是名符其实的胶水语言。例如由华盛顿大学的教授主导开发的 Sage ,就是一套以代替MATLAB、Mathematica、Maple等商用科学计算软件为目的的开源系统。它通过Python结合了众多的开源科学计算软件,并通过网页浏览器提供了一个与其交互的记事本文档界面。 169 | Python的科学计算扩展库非常多,不同专业的技术人员都可以找到适合自己的扩展库。下面是我经常会用到的一个非常不完全的列表: 170 | 171 | - NumPy + SciPy + matplotlib + IPython : 这几个应该是每位开发者都应具备的扩展库。NumPy提供了多维数组以及众多的处理函数,SciPy提供了各种数值运算功能,matplotlib能绘制 出精美的二维图表,IPython则提供了一个超强的命令行,最新版的IPython还添加于Sage类似的浏览器的记事本界面(notebook)。 172 | - SciKits : 其中包括许多独立的扩展库,作为SciPy的补充。其中 scikit-learn 是一套机器学习库,包含了比较完善的文档以及众多的实例程序。 173 | - Pandas : 以Python世界中 R 的替代品为目标的数据分析库。根据其官方网站的测试,Pandas在许多方面的性能都比R要高。 174 | - ETS : 这是一套Enthought公司开发的函数库,其中的 Mayavi 能很方便地对数据进行三维可视化。 175 | - OpenCV : 这是一套计算机视觉库,目前的最新版本已经提供了十分完备的Python接口,能够调用OpenCV中众多的图像处理、模式识别函数直接对NumPy数组进行处理。 176 | 177 | 178 | ##包管理 179 | 180 | 关于Python的包管理 181 | 182 | - Eggs 格式是 setuptools 引入的一种文件格式,它使用 .egg 扩展名,用于 Python 模块的安装。 183 | - pip 是目前 python 包管理的事实标准,2008年发布。它被用作 easy_install 的替代品,但是它仍有大量的功能建立在 setuptools 组件之上。 184 | 185 | ###python requests 186 | 187 | Requests 是使用 Apache2 Licensed 许可证的 HTTP 库。用 Python 编写,真正的为人类着想。 188 | 189 | Python 标准库中的 urllib2 模块提供了你所需要的大多数 HTTP 功能,但是它的 API太渣了。它是为另一个时代、另一个互联网所创建的。它需要巨量的工作,甚至包括各种方法覆盖,来完成最简单的任务。 190 | 191 | 以安装requests为例: 192 | 193 | 命令: 194 | 195 | ```bash 196 | sudo pip install requests 197 | ``` 198 | 199 | 结果: 200 | 201 | ```bash 202 | Downloading/unpacking requests 203 | Downloading requests-2.4.3-py2.py3-none-any.whl (459kB): 459kB downloaded 204 | Installing collected packages: requests 205 | Successfully installed requests 206 | Cleaning up... 207 | ``` 208 | 209 | 用这个库我们可以做些什么?看看官网的示例: 210 | 211 | ```bash 212 | >>> import requests 213 | >>> r = requests.get('https://github.com/timeline.json') 214 | >>> r.json() 215 | ``` 216 | 217 | 到现在你会发现我们没有说到任何的Python语法,这不是一本关于Python语法的书,如我们在开头所说的。下面是我们将会在后面用到的代码 218 | 219 | ```python 220 | #!/usr/bin/env python 221 | import requests 222 | 223 | url = "http://b.phodal.com/athome/1" 224 | r = requests.get(url) 225 | print r.text 226 | ``` 227 | -------------------------------------------------------------------------------- /src/2.5.frontend.md: -------------------------------------------------------------------------------- 1 | #前端显示 2 | 3 | ##库与车轮子 4 | 5 | 在多数的情况下我们都没有理由也没有必要去重新发明我们的车轮,在这时使用库会是一个比较好的做法。 6 | 7 | ##库 8 | 9 | ###jQuery 10 | 11 | > Jquery是继prototype之后又一个优秀的Javascript库。它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+),jQuery2.0及后续版本将不再支持IE6/7/8浏览器。jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供AJAX交互。jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的插件可供选择。jQuery能够使用户的html页面保持代码和html内容分离,也就是说,不用再在html里面插入一堆js来调用命令了,只需要定义id即可。 12 | 13 | 在我们的代码里用到了jQuery,然而这是一种简单而且快速有速地方法。 14 | 15 | ###jQuery Mobile 16 | 17 | > jQuery Mobile是jQuery 在手机上和平板设备上的版本。jQuery Mobile不仅会给主流移动平台带来jQuery核心库,而且会发布一个完整统一的jQuery移动UI框架。支持全球主流的移动平台。jQuery Mobile开发团队说:能开发这个项目,我们非常兴奋。移动Web太需要一个跨浏览器的框架,让开发人员开发出真正的移动Web网站。 18 | 19 | 整个展示页面由三部分组成,即``header``,``content``,``footer``。而我们主要需要关心的是content,也就是真下的内容。 20 | 21 | 我们只需要结合``HighChart``来设计我们的content就可以了,下面是一个简单地``HighChart``示例: 22 | 23 | ``` 24 |
25 | 26 | ``` 27 | 28 | 剩下的事就由``HighChart``来做。 29 | 30 | 最后代码如下所示 31 | 32 | ```HTML 33 | 34 |
35 | 36 |
37 |

基础控制

38 |
39 | 40 |
41 |

查看温度情况

42 |
43 |
44 |
45 |
46 |
47 |

Power by Phodal

48 |
49 | 50 | 51 | ``` 52 | 53 | 可以看到上面的代码与一般的HTML不同的地方是``data-role``,``data-collapsed``,``data-position``,而这些是jQuery Mobile所拥有的data属性。 54 | 55 | **data-role参数表**: 56 | rold | 详细 57 | --------------|---- 58 | page | 页面容器,其内部的mobile元素将会继承这个容器上所设置的属性 59 | header | 页面标题容器,这个容器内部可以包含文字、返回按钮、功能按钮等元素 60 | footer | 页面页脚容器,这个容器内部也可以包含文字、返回按钮、功能按钮等元素 61 | content | 页面内容容器,这是一个很宽容的容器,内部可以包含标准的html元素和jQueryMobile元素 62 | controlgroup | 将几个元素设置成一组,一般是几个相同的元素类型 63 | fieldcontain | 区域包裹容器,用增加边距和分割线的方式将容器内的元素和容器外的元素明显分隔 64 | navbar |功能导航容器,通俗的讲就是工具条 65 | listview |列表展示容器,类似手机中联系人列表的展示方式 66 | list-divider | 列表展示容器的表头,用来展示一组列表的标题,内部不可包含链接 67 | button | 按钮,将链接和普通按钮的样式设置成为jQueryMobile的风格 68 | none | 阻止框架对元素进行渲染,使元素以html原生的状态显示,主要用于form元素。 69 | 70 | 同上,我们也可以在网上找到其他相对就的属性。 71 | 72 | 73 | 74 | ##网站前台显示 75 | 76 | ###Highcharts 77 | 78 | Highcharts有以下的特点 79 | 80 | - 兼容性:兼容当今所有的浏览器,包括 iPhone、IE 和火狐等等; 81 | - 对个人用户完全免费; 82 | - 纯JS,无BS; 83 | - 支持大部分的图表类型:直线图,曲线图、区域图、区域曲线图、柱状图、饼装图、散布图; 84 | - 跨语言:不管是 PHP、Asp.net 还是 Java 都可以使用,它只需要三个文件:一个是Highcharts 85 | 的核心文件 highcharts.js,还有 a canvas emulator for IE 和 Jquery类库或者 MooTools 类库; 86 | - 提示功能:鼠标移动到图表的某一点上有提示信息; 87 | - 放大功能:选中图表部分放大,近距离观察图表; 88 | - 易用性:无需要特殊的开发技能,只需要设置一下选项就可以制作适合自己的图表; 89 | - 时间轴:可以精确到毫秒; 90 | 91 | 在这里只需将需要处理的数据存储到数组中,便可以将其渲染成为图形,下面的温度走势图便是基于Highcharts的结果: 92 | 93 | ![Temperture](./images/temperture.png) 94 | 95 | 先看看最后代码如下所示: 96 | 97 | ```javascript 98 | var dataLength = []; 99 | 100 | function drawTemp() { 101 | var zero = []; 102 | $.getJSON('/athome/', function(json) { 103 | var items = []; 104 | dataLength.push(json.length); 105 | $.each(json, function(key, val) { 106 | zero.push(val.temperature); 107 | }); 108 | chart = new Highcharts.Chart({ 109 | color: { 110 | linearGradient: { 111 | x1: 0, 112 | x2: 0, 113 | y1: 0, 114 | y1: 1 115 | }, 116 | stops: [ 117 | [0, '#003399'], 118 | [1, '#3366AA'] 119 | ] 120 | }, 121 | chart: { 122 | renderTo: 'Tchart', 123 | type: 'spline' 124 | }, 125 | title: { 126 | text: '本月温度情况' 127 | }, 128 | subtitle: { 129 | text: '' 130 | }, 131 | xAxis: { 132 | categories: [], 133 | title: { 134 | text: '' 135 | } 136 | }, 137 | yAxis: { 138 | title: { 139 | text: '温度 (°C)' 140 | } 141 | }, 142 | tooltip: { 143 | backgroundColor: '#FCFFC5', 144 | borderColor: 'black', 145 | borderRadius: 10, 146 | borderWidth: 1, 147 | enabled: true, 148 | formatter: function() { 149 | return '' + this.series.name + '
' + this.x + ': ' + this.y + '°C'; 150 | } 151 | }, 152 | legend: { 153 | layout: 'vertical', 154 | align: 'right', 155 | verticalAlign: 'top', 156 | x: -10, 157 | y: 100, 158 | borderWidth: 0 159 | }, 160 | plotOptions: { 161 | line: { 162 | dataLabels: { 163 | enabled: true 164 | }, 165 | enableMouseTracking: false 166 | } 167 | }, 168 | series: [{ 169 | name: '本月', 170 | data: zero 171 | }, { 172 | name: '对比', 173 | data: [26.0] 174 | }] 175 | }); 176 | }); 177 | }; 178 | 179 | function showTemper() { 180 | var length = dataLength[0]; 181 | $.ajax({ 182 | url: '/athome/' + length, 183 | type: 'GET', 184 | dataType: 'json', 185 | async: true, 186 | timeout: 1000, 187 | error: function() {}, 188 | success: function(sdata) { 189 | $('.temperStatus').empty(); 190 | $('.temperStatus').append(sdata.temperature); 191 | } 192 | }); 193 | }; 194 | 195 | $(document).ready(function() { 196 | setInterval("drawTemp();", 5000); 197 | setInterval("showTemper();", 800); 198 | drawTemp(); 199 | showTemper(); 200 | }); 201 | ``` 202 | 203 | 我们先把``HighChart``部分的代码删去,就变成下面的内容: 204 | 205 | ```javascript 206 | var dataLength = []; 207 | 208 | function drawTemp() { 209 | var zero = []; 210 | $.getJSON('/athome/', function(json) { 211 | var items = []; 212 | dataLength.push(json.length); 213 | $.each(json, function(key, val) { 214 | zero.push(val.temperature); 215 | }); 216 | }); 217 | }; 218 | 219 | function showTemper() { 220 | var length = dataLength[0]; 221 | $.ajax({ 222 | url: '/athome/' + length, 223 | type: 'GET', 224 | dataType: 'json', 225 | async: true, 226 | timeout: 1000, 227 | error: function() {}, 228 | success: function(sdata) { 229 | $('.temperStatus').empty(); 230 | $('.temperStatus').append(sdata.temperature); 231 | } 232 | }); 233 | }; 234 | 235 | $(document).ready(function() { 236 | setInterval("drawTemp();", 5000); 237 | setInterval("showTemper();", 800); 238 | drawTemp(); 239 | showTemper(); 240 | }); 241 | ``` 242 | 243 | 代码看上去是由两部分组成的``drawTemperature``和``showTemperature`` 244 | 245 | 246 | ###实时数据 247 | 248 | 剥离后的Ajax部分代码如下所示,主要用的是jQuery框架的getJSON来实现的 249 | 250 | ``` 251 | var dataLength = []; 252 | function drawTemp() { 253 | var zero = []; 254 | $.getJSON('/athome/', function(json) { 255 | var items = []; 256 | dataLength.push(json.length); 257 | $.each(json, function(key, val) { 258 | zero.push(val.temperature); 259 | }); 260 | }; 261 | ``` 262 | 263 | 实际上,我们做的只是从/athome/下面获取数据,再将数据堆到数组里面,再把这部分放到图形中。等等,什么是Ajax? 264 | 265 | AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。 266 | AJAX 不是新的编程语言,而是一种使用现有标准的新方法。 267 | AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。 268 | JSON我们前面也已经了解过了,看看getJSON吧。 269 | 270 | jQuery. getJSON 271 | 272 | 方法定义:jQuery.getJSON( url, data, callback ) 273 | 274 | 通过get请求得到json数据 275 | 276 | ·url用于提供json数据的地址页 277 | ·data(Optional)用于传送到服务器的键值对 278 | ·callback(Optional)回调函数,json数据请求成功后的处理函数 279 | 我想你似乎应该懂得了一点,就是在不刷新网页的同时,用javascript获取数据放到图表上,就这么简单。 280 | 281 | -------------------------------------------------------------------------------- /src/1.2.anywhere-javascript.md: -------------------------------------------------------------------------------- 1 | #无处不在的Javascript# 2 | 3 | Javascript现在已经无处不在了,也许你正打开的某个网站,他便可能是node.js+json+javascript+mustache.js完成的,虽然你还没理解上面那些是什么,也正是因为你不理解才需要去学习更多的东西。但是你只要知道Javascript已经无处不在了,它可能就在你手机上的某个app里,就在你浏览的网页里,就运行在你IDE中的某个进程里。 4 | 5 | ##Javascript的Hello,world## 6 | 这里我们还需要有一个helloworld.html,Javascript是专为网页交互而设计的脚本语言,所以我们一点点来开始这部分的旅途,先写一个符合标准的helloworld.html 7 | 8 | ``` html 9 | 10 | 11 | 12 | 13 | 14 | ``` 15 | 16 | 然后开始融入我们的javascript,向HTML中插入Javascript的方法,就需要用到html中的\ 25 | 26 | 27 | 28 | ``` 29 | 30 | 按照标准的写法,我们还需要声明这个脚本的类型 31 | 32 | ``` html 33 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | ``` 43 | 44 | 没有显示hello,world?试试下面的代码 45 | 46 | ``` html 47 | 48 | 49 | 50 | 53 | 54 | 55 | 58 | 59 | 60 | ``` 61 | 62 | ##更js一点### 63 | 我们需要让我们的代码看上去更像是js,同时是以js结尾。就像C语言的源码是以C结尾的,我们也同样需要让我们的代码看上去更正式一点。于是我们需要在helloworld.html的同一文件夹下创建一个app.js文件,在里面写着 64 | 65 | ``` javascript 66 | document.write('hello,world'); 67 | ``` 68 | 69 | 同时我们的helloworld.html还需要告诉我们的浏览器js代码在哪里 70 | 71 | ``` html 72 | 73 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | ``` 84 | 85 | ###从数学出发### 86 | 让我们回到第一章讲述的小明的问题,从实际问题下手编程,更容易学会编程。小学时代的数学题最喜欢这样子了——某商店里的糖一个5块钱,小明买了3个糖,小明一共花了多少钱。在编程方面,也许我们还算是小学生。最直接的方法就是直接计算3x5=? 87 | 88 | ``` javascript 89 | document.write(3*5); 90 | ``` 91 | 92 | document.write实际也我们可以理解为输出,也就是往页面里写入3*5的结果,在有双引号的情况下会输出字符串。我们便会在浏览器上看到15,这便是一个好的开始,也是一个糟糕的开始。 93 | 94 | ##设计和编程### 95 | 对于实际问题,如果我们只是止于所要得到的结果,很多年之后,我们就成为了code monkey。对这个问题进行再一次设计,所谓的设计有些时候会把简单的问题复杂化,有些时候会使以后的扩展更加简单。这一天因为这家商店的糖价格太高了,于是店长将价格降为了4块钱。 96 | 97 | ``` javascript 98 | document.write(3*4); 99 | ``` 100 | 101 | 于是我们又得到了我们的结果,但是下次我们看到这些代码的时候没有分清楚哪个是糖的数量,哪个是价格,于是我们重新设计了程序 102 | 103 | ``` javascript 104 | tang=4; 105 | num=3; 106 | document.write(tang*num); 107 | ``` 108 | 109 | 这才能叫得上是程序设计,或许你注意到了";"这个符号的存在,我想说的是这是另外一个标准,我们不得不去遵守,也不得不去fuck。 110 | 111 | ###函数### 112 | 记得刚开始学三角函数的时候,我们会写 113 | 114 | sin 30=0.5 115 | 116 | 而我们的函数也是类似于此,换句话说,因为很多搞计算机的先驱都学好了数学,都把数学世界的规律带到了计算机世界,所以我们的函数也是类似于此,让我们做一个简单的开始。 117 | 118 | ``` javascript 119 | function hello(){ 120 | return document.write("hello,world"); 121 | } 122 | hello(); 123 | ``` 124 | 125 | 当我第一次看到函数的时候,有些小激动终于出现了。我们写了一个叫hello的函数,它返回了往页面中写入hello,world的方法,然后我们调用了hello这个函数,于是页面上有了hello,world。 126 | 127 | ``` javascript 128 | function sin(degree){ 129 | return document.write(Math.sin(degree)); 130 | } 131 | sin(30); 132 | ``` 133 | 134 | 在这里degree就称之为变量。 135 | 于是输出了-0.9880316240928602,而不是0.5,因为这里用的是弧度制,而不是角度制。 136 | 137 | sin(30) 138 | 139 | 的输出结果有点类似于sin 30。写括号的目的在于,括号是为了方便解析,这个在不同的语言中可能是不一样的,比如在ruby中我们可以直接用类似于数学中的表达: 140 | 141 | ``` ruby 142 | 2.0.0-p353 :004 > Math.sin 30 143 | => -0.9880316240928618 144 | 2.0.0-p353 :005 > 145 | ``` 146 | 147 | 我们可以在函数中传入多个变量,于是我们再回到小明的问题,就会这样去编写代码。 148 | 149 | ``` javascript 150 | function calc(tang,num){ 151 | result=tang*num; 152 | document.write(result); 153 | } 154 | calc(3,4); 155 | ``` 156 | 157 | 但是从某种程度上来说,我们的calc做了计算的事又做了输出的事,总的来说设计上有些不好。 158 | 159 | ###重新设计### 160 | 我们将输出的工作移到函数的外面, 161 | 162 | ``` javascript 163 | function calc(tang,num){ 164 | return tang*num; 165 | } 166 | document.write(calc(3,4)); 167 | ``` 168 | 169 | 接着我们用一种更有意思的方法来写这个问题的解决方案 170 | 171 | ``` javascript 172 | function calc(tang,num){ 173 | return tang*num; 174 | } 175 | function printResult(tang,num){ 176 | document.write(calc(tang,num)); 177 | } 178 | printResult(3, 4) 179 | ``` 180 | 181 | 看上去更专业了一点点,如果我们只需要计算的时候我们只需要调用calc,如果我们需要输出的时候我们就调用printResult的方法。 182 | 183 | ###object和函数### 184 | 我们还没有说清楚之前我们遇到过的document.write以及Math.sin的语法为什么看上去很奇怪,所以让我们看看他们到底是什么,修改app.js为以下内容 185 | 186 | ``` javascript 187 | document.write(typeof document); 188 | document.write(typeof Math); 189 | ``` 190 | 191 | typeof document会返回document的数据类型,就会发现输出的结果是 192 | 193 | ``` javascript 194 | object object 195 | ``` 196 | 197 | 所以我们需要去弄清楚什么是object。对象的定义是 198 | 199 |
无序属性的集合,其属性可以包含基本值、对象或者函数。
200 | 201 | 创建一个object,然后观察这便是我们接下来要做的 202 | 203 | ``` javascript 204 | store={}; 205 | store.tang=4; 206 | store.num=3; 207 | document.write(store.tang*store.num); 208 | ``` 209 | 210 | 我们就有了和document.write一样的用法,这也是对象的美妙之处,只是这里的对象只是包含着基本值,因为 211 | 212 | typeof story.tang="number" 213 | 214 | 一个包含对象的对象应该是这样子的。 215 | 216 | ``` javascript 217 | store={}; 218 | store.tang=4; 219 | store.num=3; 220 | document.writeln(store.tang*store.num); 221 | 222 | var wall=new Object(); 223 | wall.store=store; 224 | document.write(typeof wall.store); 225 | ``` 226 | 227 | 而我们用到的document.write和上面用到的document.writeln都是属于这个无序属性集合中的函数。 228 | 229 | 下面代码说的就是这个无序属性集中中的函数。 230 | 231 | ``` javascript 232 | var IO=new Object(); 233 | function print(result){ 234 | document.write(result); 235 | }; 236 | IO.print=print; 237 | IO.print("a obejct with function"); 238 | IO.print(typeof IO.print); 239 | ``` 240 | 241 | 我们定义了一个叫IO的对象,声明对象可以用 242 | 243 | var store={}; 244 | 245 | 又或者是 246 | 247 | var store=new Object{}; 248 | 249 | 两者是等价的,但是用后者的可读性会更好一点,我们定义了一个叫print的函数,他的作用也就是document.write,IO中的print函数是等价于print()函数,这也就是对象和函数之间的一些区别,对象可以包含函数,对象是无序属性的集合,其属性可以包含基本值、对象或者函数。 250 | 251 | 复杂一点的对象应该是下面这样的一种情况。 252 | 253 | ``` javascript 254 | var Person={name:"phodal",weight:50,height:166}; 255 | function dream(){ 256 | future; 257 | }; 258 | Person.future=dream; 259 | document.write(typeof Person); 260 | document.write(Person.future); 261 | ``` 262 | 263 | 而这些会在我们未来的实际编程过程中用得更多。 264 | 265 | ###面向对象### 266 | 267 | 开始之前先让我们简化上面的代码, 268 | 269 | ``` javascript 270 | Person.future=function dream(){ 271 | future; 272 | } 273 | ``` 274 | 275 | 看上去比上面的简单多了,不过我们还可以简化为下面的代码。。。 276 | 277 | ``` javascript 278 | var Person=function(){ 279 | this.name="phodal"; 280 | this.weight=50; 281 | this.height=166; 282 | this.future=function dream(){ 283 | return "future"; 284 | }; 285 | }; 286 | var person=new Person(); 287 | document.write(person.name+"
"); 288 | document.write(typeof person+"
"); 289 | document.write(typeof person.future+"
"); 290 | document.write(person.future()+"
"); 291 | ``` 292 | 293 | 只是在这个时候Person是一个函数,但是我们声明的person却变成了一个对象一个Javascript函数也是一个对象,并且,所有的对象从技术上讲也只不过是函数。这里的"\"是HTML中的元素,称之为DOM,在这里起的是换行的作用,我们会在稍后介绍它,这里我们先关心下this。this关键字表示函数的所有者或作用域,也就是这里的Person。 294 | 295 | 上面的方法显得有点不可取,换句话说和一开始的 296 | 297 | document.write(3*4); 298 | 299 | 一样,不具有灵活性,因此在我们完成功能之后,我们需要对其进行优化,这就是程序设计的真谛——解决完实际问题后,我们需要开始真正的设计,而不是解决问题时的编程。 300 | 301 | ``` javascript 302 | var Person=function(name,weight,height){ 303 | this.name=name; 304 | this.weight=weight; 305 | this.height=height; 306 | this.future=function(){ 307 | return "future"; 308 | }; 309 | }; 310 | var phodal=new Person("phodal",50,166); 311 | document.write(phodal.name+"
"); 312 | document.write(phodal.weight+"
"); 313 | document.write(phodal.height+"
"); 314 | document.write(phodal.future()+"
"); 315 | ``` 316 | 317 | 于是,产生了这样一个可重用的Javascript对象,this关键字确立了属性的所有者。 318 | 319 | ##其他 320 | 321 | Javascript还有一个很强大的特性,也就是原型继承,不过这里我们先不考虑这些部分,用尽量少的代码及关键字来实际我们所要表达的核心功能,这才是这里的核心,其他的东西我们可以从其他书本上学到。 322 | 323 | 所谓的继承, 324 | 325 | ``` javascript 326 | var Chinese=function(){ 327 | this.country="China"; 328 | } 329 | 330 | var Person=function(name,weight,height){ 331 | this.name=name; 332 | this.weight=weight; 333 | this.height=height; 334 | this.futrue=function(){ 335 | return "future"; 336 | } 337 | } 338 | Chinese.prototype=new Person(); 339 | 340 | var phodal=new Chinese("phodal",50,166); 341 | document.write(phodal.country); 342 | ``` 343 | 344 | 完整的Javascript应该由下列三个部分组成: 345 | 346 | - 核心(ECMAScript)——核心语言功能 347 | - 文档对象模型(DOM)——访问和操作网页内容的方法和接口 348 | - 浏览器对象模型(BOM)——与浏览器交互的方法和接口 349 | 350 | 我们在上面讲的都是ECMAScript,也就是语法相关的,但是JS真正强大的,或者说我们最需要的可能就是对DOM的操作,这也就是为什么jQuery等库可以流行的原因之一,而核心语言功能才是真正在哪里都适用的,至于BOM,真正用到的机会很少,因为没有完善的统一的标准。 351 | 352 | 一个简单的DOM示例, 353 | 354 | ``` html 355 | 356 | 357 | 358 | 359 | 360 | 363 |

Red

364 | 365 | 366 | 367 | ``` 368 | 369 | 我们需要修改一下helloworld.html添加 370 | 371 | ```HTML 372 |

Red

373 | ``` 374 | 375 | 同时还需要将script标签移到body下面,如果没有意外的话我们会看到页面上用红色的字体显示Red,修改app.js。 376 | 377 | ``` javascript 378 | var para=document.getElementById("para"); 379 | para.style.color="blue"; 380 | ``` 381 | 382 | 接着,字体就变成了蓝色,有了DOM我们就可以对页面进行操作,可以说我们看到的绝大部分的页面效果都是通过DOM操作实现的。 383 | 384 | ##美妙之处## 385 | 这里说到的Javascript仅仅只是其中的一小小部分,忽略掉的东西很多,只关心的是如何去设计一个实用的app,作为一门编程语言,他还有其他强大的内制函数,要学好需要一本有价值的参考书。这里提到的只是其中的不到20%的东西,其他的80%或者更多会在你解决问题的时候出现。 386 | 387 | - 我们可以创建一个对象或者函数,它可以包含基本值、对象或者函数。 388 | - 我们可以用Javascript修改页面的属性,虽然只是简单的示例。 389 | - 我们还可以去解决实际的编程问题。 390 | -------------------------------------------------------------------------------- /src/2.3.create_laravel.md: -------------------------------------------------------------------------------- 1 | #创建REST服务 2 | 3 | ##数据库迁移 4 | 5 | 这个名字是源自于Ruby On Rails在那时候的印象,不直接使用MySQL的目的在于让我们可以专注于过程。 6 | 7 | ###创建表 8 | 9 | 表的概念,类似于在Excel中的表,如果你真实不懂数据库。 10 | 让我们创建一个athomes的表,为什么是athomes,因为以前在写android程序的时候就叫的是athome,忽略掉这些次要的因素吧。 11 | 12 | ```bash 13 | $ php artisan migrate:make create_athomes_table 14 | ``` 15 | 16 | 打开 app/database/migrations/***create_athomes_table.php这里的***是由日期和某些东西组成的,修改生成的代码为下面。 17 | 18 | ```php 19 | use Illuminate\Database\Schema\Blueprint; 20 | use Illuminate\Database\Migrations\Migration; 21 | 22 | class CreateAthomesTable extends Migration { 23 | public function up() 24 | { 25 | Schema::create('athomes', function(Blueprint $table) 26 | { 27 | $table--->increments('id'); 28 | $table->float('temperature'); 29 | $table->float('sensors1'); 30 | $table->float('sensors2'); 31 | $table->boolean('led1'); 32 | $table->timestamps(); 33 | }); 34 | } 35 | public function down() 36 | { 37 | Schema::drop('athomes'); 38 | } 39 | } 40 | ``` 41 | 42 | 意思大致就是id是自加的,也就是我们在localhost/athome/{id},当我们创建一个新的数据的时候,会自动加上去,最后一个timestamps批的是时间,会包含创建时间和修改时间。 43 | 剩下的temperature,sensors1,sensors2是小数,以及只有真和假的led1。 44 | 45 | ###数据库迁移 46 | 47 | 我们只是写了我们需要的数据的格式而并没有丢到数据库里, 48 | 49 | ```bash 50 | $ php artisan migrate 51 | ``` 52 | 53 | 这个就是我们执行迁移的命令,如果你用phpmyadmin可以直接打开查看,没有的话,可以。 54 | 55 | ```bash 56 | $ mysql -uroot -p 57 | ``` 58 | 59 | ```sql 60 | use iot; 61 | select * from athomes; 62 | ``` 63 | 64 | 就可以看到我们写的东西,那么接下来就是创建RESTful服务了 65 | 66 | 67 | ##创建RESTful 68 | 69 | 用下面的代码实现我们称之为Athomes控制器的创建 70 | 71 | ```bash 72 | $ php artisan controller:make AthomesController 73 | ``` 74 | 75 | 就会在app/controllers下面生成下面的代码 76 | 77 | ```php 78 | class AthomesController extends \BaseController { 79 | public function index() {} 80 | public function create() {} 81 | public function store() {} 82 | public function show($id) {} 83 | public function edit($id) {} 84 | public function update($id) {} 85 | public function destroy($id) {} 86 | } 87 | ``` 88 | 89 | ##Laravel Resources 90 | 91 | 上面的代码过于沉重,请让我用 Ctrl+C 来带来点知识吧。 92 | 93 | Verb | Path | Action | Route Name 94 | ------|--------|---------|----------- 95 | GET | /resource | index | resource.index 96 | GET | /resource/create | create | resource.create 97 | POST | /resource | store | resource.store 98 | GET | /resource/{resource} | show | resource.show 99 | GET | /resource/{resource}/edit | edit | resource.edit 100 | PUT/PATCH | /resource/{resource} | update | resource.update 101 | DELETE | /resource/{resource} | destroy | resource.destroy 102 | 103 | 所以我们只需要专注于创建 create, edit, show, destory 等等。好吧,你可能没有耐心了,但是在修改这个之前我们需要先在 104 | app/model 加个 class 105 | 106 | ```php 107 | class Athomes extends Eloquent { 108 | protected $table = 'athomes'; 109 | } 110 | ``` 111 | 112 | 如果你想要的只是控制器Athomes的代码的话。。 113 | 114 | ```php 115 | class AthomesController extends \BaseController { 116 | public $restful=true; 117 | protected $athome; 118 | public function __construct(Athomes $athome) 119 | { 120 | $this--->athome = $athome ; 121 | } 122 | public function index() 123 | { 124 | $maxid=Athomes::all(); 125 | return Response::json($maxid); 126 | } 127 | public function create() 128 | { 129 | $maxid=Athomes::max('id'); 130 | return View::make('athome.create')->with('maxid',$maxid); 131 | } 132 | public function store() 133 | { 134 | $rules = array( 135 | 'led1'=>'required', 136 | 'sensors1' => 'required|numeric|Min:-50|Max:80', 137 | 'sensors2' => 'required|numeric|Min:-50|Max:80', 138 | 'temperature' => 'required|numeric|Min:-50|Max:80' 139 | ); 140 | $validator = Validator::make(Input::all(), $rules); 141 | if ($validator->fails()) { 142 | return Redirect::to('athome/create') 143 | ->withErrors($validator) 144 | ->withInput(Input::except('password')); 145 | } else { 146 | $nerd = new Athomes; 147 | $nerd->sensors1 = Input::get('sensors1'); 148 | $nerd->sensors2 = Input::get('sensors2'); 149 | $nerd->temperature = Input::get('temperature'); 150 | $nerd->led1 = Input::get('led1'); 151 | $nerd->save(); 152 | Session::flash('message', 'Successfully created athome!'); 153 | return Redirect::to('athome'); 154 | } 155 | } 156 | public function show($id) 157 | { 158 | $myid=Athomes::find($id); 159 | $maxid=Athomes::where('id','=',$id) 160 | ->select('id','temperature','sensors1','sensors2','led1') 161 | ->get(); 162 | return Response::json($maxid); 163 | } 164 | public function edit($id) 165 | { 166 | $athome = Athomes::find($id); 167 | return View::make('athome.edit') 168 | ->with('athome', $athome); 169 | } 170 | public function update($id) 171 | { 172 | $rules = array( 173 | 'led1'=>'required|', 174 | 'sensors1' => 'required|numeric|Min:-50|Max:80', 175 | 'sensors2' => 'required|numeric|Min:-50|Max:80', 176 | 'temperature' => 'required|numeric|Min:-50|Max:80' 177 | ); 178 | $validator = Validator::make(Input::all(), $rules); 179 | if ($validator->fails()) { 180 | return Redirect::to('athome/' . $id . '/edit') 181 | ->withErrors($validator); 182 | } else { 183 | $nerd = Athomes::find($id); 184 | $nerd->sensors1 = Input::get('sensors1'); 185 | $nerd->sensors2 = Input::get('sensors2'); 186 | $nerd->temperature = Input::get('temperature'); 187 | $nerd->led1 = Input::get('led1'); 188 | $nerd->save(); 189 | Session::flash('message', 'Successfully created athome!'); 190 | return Redirect::to('athome'); 191 | } 192 | } 193 | public function destroy($id) 194 | { 195 | $athome = Athomes::find($id); 196 | $athome->delete(); 197 | if(is_null($athome)) 198 | { 199 | return Response::json('Todo not found', 404); 200 | } 201 | Session::flash('message', 'Successfully deleted the nerd!'); 202 | return Redirect::to('athome'); 203 | } 204 | } 205 | ``` 206 | 207 | 希望你能读懂,没有的话,继续。 208 | 209 | 下面这部分来自于之前的博客,这里就不多加论述了。 210 | 这个也就是我们要的模板, 211 | 212 | ###修改Create() 213 | 214 | ```php 215 | public function create() 216 | { 217 | $maxid=Athomes::max('id'); 218 | return View::make('athome.create')->with('maxid',$maxid); 219 | } 220 | ``` 221 | 222 | 223 | 这里需要在app/views/创建一个athome里面创建一个create.blade.php,至于maxid,暂时还不需要,后面会用到show。如果只需要模板,可以简化为 224 | 225 | ```php 226 | public function create() 227 | { 228 | return View::make('athome.create'); 229 | } 230 | ``` 231 | 232 | 这里只是对其中代码的进行一下说明。 233 | 234 | ###创建表单 235 | 236 | ####创建表单之前 237 | 238 | 由于使用到了bootstrap以及bootstrap-select,记得添加css。 239 | 240 | ```html 241 | 242 | 243 | ``` 244 | 245 | 以及javascript 246 | 247 | ```html 248 | 249 | 250 | 251 | 254 | ``` 255 | 256 | ####创建表单 257 | 258 | 这里用到的是之前提到的那个作者写下的,稍微修改了一下。 259 | 260 | ```html 261 |
262 | {{ HTML::ul($errors->all()) }} 263 | {{ Form::open(array('url' => 'athome')) }} 264 |
265 | {{ Form::label('led1', '开关1') }} 266 | {{ Form::select('led1',array('关','开'),$selected=NULL,array('class'=>'selectpicker')) }} 267 |
268 |
269 | {{ Form::label('sensors1', 'sensors1') }} 270 | {{ Form::text('sensors1', Input::old('sensors1'), array('class' => 'form-control')) }} 271 |
272 |
273 | {{ Form::label('sensors2', 'sensors2') }} 274 | {{ Form::text('sensors2', Input::old('sensors2'), array('class' => 'form-control')) }} 275 |
276 |
277 | {{ Form::label('temperature', 'temperature') }} 278 | {{ Form::text('temperature', Input::old('temperature'), array('class' => 'form-control')) }} 279 |
280 | {{ Form::submit('Create!', array('class' => 'btn btn-primary')) }} 281 | {{ Form::close() }} 282 |
283 | ``` 284 | 285 | 开关一开始打算用 checkbox,加上 bootstrap-switch 实现 286 | ON OFF 287 | 弱弱地觉得还是没掌握好的节奏,所以最后用 select 来实现。 288 | 289 | 还需要修改一下之前的 create(),添加一行 290 | 291 | ```php 292 | return Redirect::to('athome'); 293 | ``` 294 | 295 | 也就是添加完后,重定向到首页查看,最后例子给出的 create 如下 296 | 297 | ```php 298 | public function store() 299 | { 300 | $rules = array( 301 | 'led1'=>'required', 302 | 'sensors1' => 'required|numeric|Min:-50|Max:80', 303 | 'sensors2' => 'required|numeric|Min:-50|Max:80', 304 | 'temperature' => 'required|numeric|Min:-50|Max:80' 305 | ); 306 | $validator = Validator::make(Input::all(), $rules); 307 | if ($validator->fails()) { 308 | return Redirect::to('athome/create') 309 | ->withErrors($validator); 310 | } else { 311 | // store 312 | $nerd = new Athomes; 313 | $nerd->sensors1 = Input::get('sensors1'); 314 | $nerd->sensors2 = Input::get('sensors2'); 315 | $nerd->temperature = Input::get('temperature'); 316 | $nerd->led1 = Input::get('led1'); 317 | $nerd->save(); 318 | Session::flash('message', 'Successfully created athome!'); 319 | return Redirect::to('athome'); 320 | } 321 | } 322 | ``` 323 | 324 | ###编辑模板 325 | 326 | 完整的 blade 模板文件 327 | 328 | ```html 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | @yield('title') 337 | 338 | 339 | 340 | 341 | 342 |
343 |
344 |
345 |

Edit {{ $athome->id }}

346 | 347 | {{ HTML::ul($errors->all()) }} 348 | {{ Form::model($athome, array('route' => array('athome.update', $athome->id), 'method' => 'PUT')) }} 349 |
350 | {{ Form::label('led1', '开关1') }} 351 | {{ Form::select('led1',array('关','开'),$selected=NULL,array('class'=>'selectpicker')) }} 352 |
353 |
354 | {{ Form::label('sensors1', '传感器1') }} 355 | {{ Form::text('sensors1', Input::old('sensors1'), array('class' => 'form-control')) }} 356 |
357 |
358 | {{ Form::label('sensors2', '传感器2') }} 359 | {{ Form::text('sensors2', Input::old('sensors2'), array('class' => 'form-control')) }} 360 |
361 |
362 | {{ Form::label('temperature', '温度传感器') }} 363 | {{ Form::text('temperature', Input::old('temperature'), array('class' => 'form-control')) }} 364 |
365 | {{ Form::submit('Edit the Nerd!', array('class' => 'btn btn-primary')) }} 366 | {{ Form::close() }} 367 |
368 |
369 | 372 |
373 |
374 | 375 | 376 | 377 | 380 | 381 | 382 | 383 | ``` 384 | 385 | 效果图: 386 | 387 | ![Blade Edit](./images/edit.png) 388 | 389 | 最后效果见:[http://b.phodal.com/](http://b.phodal.com/) 390 | -------------------------------------------------------------------------------- /src/1.5.linux.md: -------------------------------------------------------------------------------- 1 | #GNU/Linux 强大且Free 2 | 3 | ![GNU/Linux](./images/gnu_linux.png) 4 | 5 | ##什么是Linux 6 | 7 | Linux是一种自由和开放源码的类UNIX操作系统内核。目前存在着许多不同的Linux发行版,可安装在各种各样的电脑硬件设备,从手机、平板电脑、路由器和影音游戏控制台,到桌上型电脑,大型电脑和超级电脑。 8 | Linux是一个领先的操作系统内核,世界上运算最快的10台超级电脑运行的都是基于Linux内核的操作系统。 9 | 10 | Linux操作系统也是自由软件和开放源代码发展中最著名的例子。只要遵循GNU通用公共许可证,任何人和机构都可以自由地使用Linux的所有底层源代码,也可以自由地修改和再发布。**严格来讲,Linux这个词本身只表示Linux内核,但在实际上人们已经习惯了用Linux来形容整个基于Linux内核,并且使用GNU工程各种工具和数据库的操作系统(也被称为GNU/Linux)。**通常情况下,Linux被打包成供桌上型电脑和服务器使用的Linux发行版本。一些流行的主流Linux发行版本,包括Debian(及其衍生版本Ubuntu),Fedora和openSUSE等。Linux得名于电脑业余爱好者Linus Torvalds。 11 | 12 | 而不是如百度百科所讲的~~Linux操作系统是UNIX操作系统的一种克隆系统。它诞生于1991年的 Linux桌面[1]10 月5日(这是第一次正式向外公布的时间)。以后借助于Internet网络,并通过全世界各地计算机爱好者的共同努力,已成为今天世界上使用最多的一种UNIX类操作系统,并且使用人数还在迅猛增长。~~ 13 | 14 | Linux只是个内核,而不是操作系统,所以在这我们再理解一下操作系统是由什么组成的。 15 | 16 | ##操作系统 17 | 18 | 操作系统(英语:Operating 19 | System,简称OS)是管理计算机硬件与软件资源的计算机程序,同时也是计算机系统的内核与基石。操作系统需要处理如管理与配置内存、决定系统资源供需的优先次序、控制输入与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。 20 | 操作系统的型态非常多样,不同机器安装的操作系统可从简单到复杂,可从手机的嵌入式系统到超级计算机的大型操作系统。许多操作系统制造者对它涵盖范畴的定义也不尽一致,例如有些操作系统集成了图形用户界面(GUI),而有些仅使用命令行界面(CLI),而将GUI视为一种非必要的应用程序。 21 | 22 | 操作系统位于底层硬件与用户之间,是两者沟通的桥梁。用户可以通过操作系统的用户界面,输入命令。操作系统则对命令进行解释,驱动硬件设备,实现用户要求。以现代标准而言,一个标准PC的操作系统应该提供以下的功能: 23 | 24 | - 进程管理(Processing management) 25 | - 内存管理(Memory management) 26 | - 文件系统(File system) 27 | - 网络通信(Networking) 28 | - 安全机制(Security) 29 | - 用户界面(User interface) 30 | - 驱动程序(Device drivers) 31 | 32 | 而让我们来看一下两者之间的不同之处,这是一张linux的架构图我们可以发现内核只是位于底层。 33 | 34 | ###Linux架构图 35 | 36 | ![Linux Kernel](./images/linux_kernel.jpg) 37 | 38 | ####用户模式 39 | 40 | 应用程序(sh、[vi](http://zh.wikipedia.org/wiki/Vi "Vi")、[OpenOffice.org](http://zh.wikipedia.org/wiki/OpenOffice.org "OpenOffice.org")等) 41 | 42 | 复杂[库](http://zh.wikipedia.org/wiki/%E5%BA%93 "库")([KDE](http://zh.wikipedia.org/wiki/KDE "KDE")、glib等) 43 | 简单库(opendbm、sin等) 44 | 45 | C库(open、fopen、socket、exec、calloc等) 46 | 47 | ####内核模式 48 | 49 | - 系统中断、调用、错误等软硬件消息 50 | - 内核(驱动程序、进程、网络、内存管理等) 51 | - 硬件(处理器、内存、各种设备) 52 | 53 | 我们可以发现,由linux内核+shell可以构成一个操作系统,而linux本身只是个内核,也就是图中的内核模式,负责控制系统的这些部分。也就是我们可以发现,Linux内核构成了一个操作系统除用户界面以外的部分,而shell就是这最后的用户界面。 54 | 55 | 而linux内核以外的部分就是由GNU计划构成的。 56 | 57 | ###Shell 58 | 59 | ![Shell](./images/shell.png) 60 | 61 | Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。 62 | 63 | 实际上Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核。不仅如此,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令组成的程序。Shell编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果 64 | 65 | bash 是一个为GNU计划编写的Unix shell。它的名字是一系列缩写:Bourne-Again SHell — 这是关于Bourne shell(sh)的一个双关语(Bourne again / born 66 | again)。Bourne shell是一个早期的重要shell,由史蒂夫·伯恩在1978年前后编写,并同Version 7 Unix一起发布。bash则在1987年由布莱恩·福克斯创造。在1990年,Chet Ramey成为了主要的维护者。 67 | 68 | shell将会是我们在GNU/linux中经常用到的经常有到的工具之一,用来操作计算机用的。在迁移到linux之前我们可以试用cygwin来进行模拟: 69 | 70 | Cygwin是许多自由软件的集合,最初由Cygnus Solutions开发,用于各种版本的Microsoft Windows上,运行``UNIX类``系统。 71 | 72 | ###GCC 73 | 74 | GCC(GNU Compiler Collection,GNU编译器套装),是一套由GNU开发的编程语言编译器。它是一套以GPL及LGPL许可证所发行的自由软件,也是GNU计划的关键部分,亦是自由的类Unix及苹果电脑Mac OS X 操作系统的标准编译器。GCC(特别是其中的C语言编译器)也常被认为是跨平台编译器的事实标准。 75 | 76 | GCC原名为GNU C语言编译器(GNU C Compiler),因为它原本只能处理C语言。GCC很快地扩展,变得可处理C++。之后也变得可处理Fortran、Pascal、Objective-C、Java、Ada,以及Go与其他语言。 77 | 78 | ```c 79 | #include 80 | main() 81 | { 82 | printf("Hello world\n"); 83 | } 84 | ``` 85 | 86 | ```bash 87 | ~/temp/free> gcc hello.c -o hello 88 | hello.c:2:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int] 89 | main() 90 | ^~~~ 91 | 1 warning generated. 92 | ~/temp/free> ./hello 93 | Hello world 94 | ``` 95 | 96 | 同shell一样,对于GNU/linux系统而言,GCC的作用也是无可取代的。当然如果只是一般用途的话,GCC对于一般用户可能没用,但是在些GNU/Linux系统上,我们可能就需要自己编译源码成二进制文件,而没有软件包,因而其重要性是不言而喻的。自然的如果我们自己动手编译GNU/Linux操作系统的话,我们会理解其的重要意义。有兴趣的同学可以试一下:Linux 97 | From Scratch (LFS)。 98 | 99 | ###启动引导程序 100 | 101 | 最后,当我们构成以上的那些之后,我们就需要一个引导程序,以便使系统启动,引导进内核。 102 | 103 | 启动程序(bootloader)于电脑或其他计算机应用上,是指引导操作系统启动的程序。启动程序启动方式与程序视应用机型种类。例如在普通PC上,引导程序通常分为两部分:第一阶段引导程序位于主引导记录,用于引导位于某个分区上的第二阶段引导程序,如NTLDR、GNU 104 | GRUB等。 105 | 106 | BIOS 107 | 开机完成后,bootloader就接手初始化硬件设备、创建存储器空间的映射,以便为操作系统内核准备好 108 | 109 | 正确的软硬件环境。 110 | 111 | 简单的bootloader的虚拟汇编码,如其后的八个指令: 112 | 113 | - 0: 将P暂存器的值设为8 114 | - 1: 检查纸带({paper tape)读取器,是否已经可以进行读取 115 | - 2: 如果还不能进行读取, 跳至1 116 | - 3: 从纸带读取器,读取一byte至累加器 117 | - 4: 如为带子结尾,跳至8 118 | - 5: 将暂存器的值,存储至P暂存器中的数值所指定的地址 119 | - 6: 增加P暂存器的值 120 | - 7: 跳至1 121 | 122 | 但是随着计算机操作系统越来越复杂,位于MBR的空间已经放不下引导操作系统的代码,于是就有了第二阶段的引导程序,而MBR中代码的功能也从直接引导操作系统变成了引导第二阶段的引导程序。 123 | 124 | 通常在一个GNU/Linux系统中选用GNUGRUB做为引导程序,例如Ubuntu就是用GRUB2。 125 | 126 | GNU GRUB(简称“GRUB”)是一个来自GNU项目的启动引导程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。 127 | 128 | GNU GRUB的前身为Grand Unified Bootloader。它主要用于类Unix系统;同大多Linux发行版一样,GNU系统也采用GNU GRUB作为它的启动器。Solaris从10 1/06版开始在x86系统上也采用GNU GRUB作为启动器。 129 | 130 | 以上也就构成了一个简单的操作系统。 131 | 132 | ##从编译开始 133 | 134 | 我们以一次编译开始我们的Linux学习之旅。 135 | 136 | ###开始之前 137 | 138 | - 如果你没有用过GNU/Linux,我想你需要在虚拟机上安装一个。 139 | - 一个主流的GNU/Linux发行版,如Ubuntu,CentOS,Debian,Mint,OpenSUSE,Fedora等等。 140 | - 学会如何打开shell(ps:bash,zsh,sh等等)。 141 | 142 | 或者你也可以在Windows上安装Cygwin。 143 | 144 | ###编译Nginx 145 | 146 | 1.下载这个软件的源码包 147 | 148 | ```bash 149 | wget http://nginx.org/download/nginx-1.7.4.tar.gz 150 | ``` 151 | wget是一个用于下载的软件,当然你也可以用软件,只是用wget似乎会比图形界面快哦。 152 | 153 | 2.解压软件包 154 | 155 | ```bash 156 | tar -vf nginx-1.7.4.tar.gz 157 | ``` 158 | 159 | -vf的意思是Extract,也就是解压,而tar则是这个解压软件的名字。看上去似乎比WinRAR来得复制得多,但是你可以计时一下,从下载到解压完,和你用鼠标比哪个比较快。 160 | 161 | 3.到nginx目录下 162 | 163 | 这里需要分两部进行 164 | 165 | 1).列出所有文件 166 | 167 | ```bash 168 | ls -al 169 | 170 | drwxr-xr-x 15 fdhuang staff 510B Sep 2 13:44 nginx-1.7.4 171 | -rw-r--r-- 1 fdhuang staff 798K Aug 5 21:55 nginx-1.7.4.tar.gz 172 | ``` 173 | 174 | 2).到nginx-1.7.4目录 175 | 176 | ```bash 177 | cd nginx-1.7.4 178 | ``` 179 | 180 | 4.配置nginx 181 | 182 | 一次简单的配置如下 183 | 184 | ```bash 185 | ./configure 186 | ``` 187 | 188 | 当你熟练以后,你可能和我一样用下面的配置(``注意``:用下面的代码会出错。) 189 | 190 | ```bash 191 | ./configure --user=www --group=www --add-module=../ngx_pagespeed-1.8.3.4-beta --add-module=../ngx_cache_purge --prefix=/usr/local/nginx --with-pcre --with-http_spdy_module --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-mail --with-mail_ssl_module --with-ipv6 192 | ``` 193 | 194 | 过程中可能会提示你其中出了多少错误,而这时你便可以很愉快地去用搜索引擎搜索他们。 195 | 196 | 5.make 197 | 198 | 这里就会用到GCC等等。 199 | 200 | ```bash 201 | make 202 | ``` 203 | 204 | 6.运行 205 | 206 | 如果运行顺利的话,应该可以直接 207 | 208 | ```bash 209 | ./objs/nginx 210 | ``` 211 | 212 | ###其他 213 | 214 | 1.如果没有wget,make,gcc等命令的时候可以用类似于下面的方法安装, 215 | 216 | ```bash 217 | sudo apt-get install gcc,make,wget 218 | ``` 219 | 220 | 2.正常情况下一个开源项目都会有一个README,会告诉你应该如何去做。 221 | 222 | ##包管理 223 | 224 | GNU/Linux最方便的东西莫过于包管理了。 225 | 226 | 引自OpenSUSE官网的说明及图片[^pm] 227 | 228 | [^pm]:https://zh.opensuse.org/index.php?title=%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%AE%A1%E7%90%86&variant=zh 229 | 230 | ![package management](http://ebook.designiot.cn/images/pm.png) 231 | 232 | 1. Linux 发行版无非就是一堆软件包 (package) 形式的应用程序加上整体地管理这些应用程序的工具。通常这些 Linux 发行版,包括 openSUSE,都是由成千上万不同的软件包构成的。 233 | 234 | 2. 软件包: 软件包不止是一个文件,内含构成软件的所有文件,包括程序本身、共享库、开发包以及使用说明等。 235 | 236 | 3. 元数据 (metadata) 包含于软件包之中,包含软件正常运行所需要的一些信息。软件包安装之后,其元数据就存储于本地的软件包数据库之中,以用于软件包检索。 237 | 238 | 4. 依赖关系 (dependencies) 是软件包管理的一个重要方面。实际上每个软件包都会涉及到其他的软件包,软件包里程序的运行需要有一个可执行的环境(要求有其他的程序、库等),软件包依赖关系正是用来描述这种关系的。 239 | 240 | Linux 下的软件包通常是以下三种格式: 241 | 242 | - tgz - tar gzip 文件。这类文件是基本的压缩软件包,可以容纳软件包维护者认为有用的所有的东西。此格式除本身的压缩格式外,并没有有关软件包内容的标准。 243 | - deb - 此格式的软件包常用于 Debian 系统,是标准的 Debian 软件包格式。 244 | - rpm - 此格式由 Red Hat Linux 所创建,并经由 LSB 标准化,现已为众多 Linux 发行版所采用,是一个优秀的软件包格式。openSUSE 即是用此格式。更多信息可以参阅此处。 245 | 246 | > 所以这就需要能自动解决依赖关系的软件包管理器。软件包管理系统就是一个工具集,为系统提供一个统一的安装、升级、删除软件的方式。 247 | 248 | ##Ubuntu LNMP 249 | 250 | 在余下的章节中,我们需要去部署,需要去使用Ubuntu。如果在Windows下可以使用LAMP,但是在这里我们只说Ubuntu。开始之前你需要安装好Ubuntu,无论是在虚拟机,还是在真机安装,或者是Docker。 251 | 252 | ###Update软件包列表 253 | 254 | ``apt-get``是debian,ubuntu发行版的包管理工具。``apt-get update``可以确保我们的软件包列表是最新的,下面是一个简单的更新过程。 255 | 256 | 打开Terminal或者Konsole等等之类的终端控制台。 257 | 258 | ```bash 259 | root@70cdc7a176a5:/# sudo apt-get update 260 | Ign http://archive.ubuntu.com trusty InRelease 261 | Ign http://archive.ubuntu.com trusty-updates InRelease 262 | Ign http://archive.ubuntu.com trusty-security InRelease 263 | Ign http://archive.ubuntu.com trusty-proposed InRelease 264 | Get:1 http://archive.ubuntu.com trusty Release.gpg [933 B] 265 | Get:2 http://archive.ubuntu.com trusty-updates Release.gpg [933 B] 266 | Get:3 http://archive.ubuntu.com trusty-security Release.gpg [933 B] 267 | Get:4 http://archive.ubuntu.com trusty-proposed Release.gpg [933 B] 268 | Get:5 http://archive.ubuntu.com trusty Release [58.5 kB] 269 | Get:6 http://archive.ubuntu.com trusty-updates Release [62.0 kB] 270 | Get:7 http://archive.ubuntu.com trusty-security Release [62.0 kB] 271 | Get:8 http://archive.ubuntu.com trusty-proposed Release [209 kB] 272 | Get:9 http://archive.ubuntu.com trusty/main Sources [1335 kB] 273 | Get:10 http://archive.ubuntu.com trusty/restricted Sources [5335 B] 274 | Get:11 http://archive.ubuntu.com trusty/universe Sources [7926 kB] 275 | Get:12 http://archive.ubuntu.com trusty/main amd64 Packages [1743 kB] 276 | Get:13 http://archive.ubuntu.com trusty/restricted amd64 Packages [16.0 kB] 277 | Get:14 http://archive.ubuntu.com trusty/universe amd64 Packages [7589 kB] 278 | 64% [14 Packages 664 kB/7589 kB 9%] 58.3 kB/s 1min 58s 279 | ``` 280 | 281 | 更新完应该会显示: 282 | 283 | ```bash 284 | Fetched 20.5 MB in 5min 22s (63.6 kB/s) 285 | Reading package lists... Done 286 | ``` 287 | 288 | ###安装MySQL 289 | 290 | 安装命令 291 | 292 | ```bash 293 | sudo apt-get install mysql-server php5-mysql 294 | ``` 295 | 过程: 296 | 297 | ```bash 298 | root@70cdc7a176a5:/# sudo apt-get install mysql-server php5-mysql 299 | Reading package lists... 0% 300 | Reading package lists... Done 301 | Building dependency tree 302 | Reading state information... Done 303 | The following extra packages will be installed: 304 | libaio1 libdbd-mysql-perl libdbi-perl libhtml-template-perl libmysqlclient18 305 | libterm-readkey-perl libwrap0 lsof mysql-client-5.5 mysql-client-core-5.5 306 | mysql-common mysql-server-5.5 mysql-server-core-5.5 php5-common php5-json 307 | psmisc tcpd 308 | Suggested packages: 309 | libclone-perl libmldbm-perl libnet-daemon-perl libplrpc-perl 310 | libsql-statement-perl libipc-sharedcache-perl tinyca mailx php5-user-cache 311 | The following NEW packages will be installed: 312 | libaio1 libdbd-mysql-perl libdbi-perl libhtml-template-perl libmysqlclient18 313 | libterm-readkey-perl libwrap0 lsof mysql-client-5.5 mysql-client-core-5.5 314 | mysql-common mysql-server mysql-server-5.5 mysql-server-core-5.5 php5-common 315 | php5-json php5-mysql psmisc tcpd 316 | 0 upgraded, 19 newly installed, 0 to remove and 12 not upgraded. 317 | Need to get 9982 kB of archives. 318 | After this operation, 99.1 MB of additional disk space will be used. 319 | Get:1 http://archive.ubuntu.com/ubuntu/ trusty/main libaio1 amd64 0.3.109-4 [6364 B] 320 | Get:2 http://archive.ubuntu.com/ubuntu/ trusty-updates/main mysql-common all 5.5.40-0ubuntu0.14.04.1 [14.1 kB] 321 | Get:3 http://archive.ubuntu.com/ubuntu/ trusty-updates/main libmysqlclient18 amd64 5.5.40-0ubuntu0.14.04.1 [598 kB] 322 | Get:4 http://archive.ubuntu.com/ubuntu/ trusty/main libwrap0 amd64 7.6.q-25 [46.2 kB] 323 | Get:5 http://archive.ubuntu.com/ubuntu/ trusty/main libdbi-perl amd64 1.630-1 [879 kB] 324 | Get:6 http://archive.ubuntu.com/ubuntu/ trusty/main libdbd-mysql-perl amd64 4.025-1 [99.3 kB] 325 | Get:7 http://archive.ubuntu.com/ubuntu/ trusty/main libterm-readkey-perl amd64 2.31-1 [27.4 kB] 326 | Get:8 http://archive.ubuntu.com/ubuntu/ trusty-updates/main mysql-client-core-5.5 amd64 5.5.40-0ubuntu0.14.04.1 [703 kB] 327 | Get:9 http://archive.ubuntu.com/ubuntu/ trusty-updates/main mysql-client-5.5 amd64 5.5.40-0ubuntu0.14.04.1 [1466 kB] 328 | Get:10 http://archive.ubuntu.com/ubuntu/ trusty-updates/main mysql-server-core-5.5 amd64 5.5.40-0ubuntu0.14.04.1 [3215 kB] 329 | 47% [10 mysql-server-core-5.5 850 kB/3215 kB 26%] 79.9 kB/s 1min 6s 330 | ``` 331 | 332 | 在安装的过程中会要求你输入数据库密码。(默认为空) 333 | 334 | ###安装Nginx 335 | 336 | ```bash 337 | echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/nginx-stable.list 338 | sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C300EE8C 339 | sudo apt-get update 340 | sudo apt-get install nginx 341 | ``` 342 | 343 | 启动Nginx Server 344 | 345 | ```bash 346 | sudo service nginx start 347 | ``` 348 | 349 | ###安装PHP 350 | 351 | sudo apt-get install php5-fpm 352 | 353 | 安装过程 354 | 355 | ```bash 356 | root@70cdc7a176a5:/# sudo apt-get install php5-fpm 357 | Reading package lists... Done 358 | Building dependency tree 359 | Reading state information... Done 360 | The following extra packages will be installed: 361 | libsystemd-daemon0 362 | Suggested packages: 363 | php-pear 364 | The following NEW packages will be installed: 365 | libsystemd-daemon0 php5-fpm 366 | 0 upgraded, 2 newly installed, 0 to remove and 12 not upgraded. 367 | Need to get 2201 kB of archives. 368 | After this operation, 9326 kB of additional disk space will be used. 369 | Do you want to continue? [Y/n] y 370 | Get:1 http://archive.ubuntu.com/ubuntu/ trusty-proposed/main libsystemd-daemon0 amd64 204-5ubuntu20.8 [9608 B] 371 | Get:2 http://archive.ubuntu.com/ubuntu/ trusty-updates/universe php5-fpm amd64 5.5.9+dfsg-1ubuntu4.5 [2191 kB] 372 | Fetched 2201 kB in 1min 5s (33.6 kB/s) 373 | Selecting previously unselected package libsystemd-daemon0:amd64. 374 | (Reading database ... 13105 files and directories currently installed.) 375 | Preparing to unpack .../libsystemd-daemon0_204-5ubuntu20.8_amd64.deb ... 376 | Unpacking libsystemd-daemon0:amd64 (204-5ubuntu20.8) ... 377 | Selecting previously unselected package php5-fpm. 378 | Preparing to unpack .../php5-fpm_5.5.9+dfsg-1ubuntu4.5_amd64.deb ... 379 | Unpacking php5-fpm (5.5.9+dfsg-1ubuntu4.5) ... 380 | Processing triggers for ureadahead (0.100.0-16) ... 381 | Setting up libsystemd-daemon0:amd64 (204-5ubuntu20.8) ... 382 | Setting up php5-fpm (5.5.9+dfsg-1ubuntu4.5) ... 383 | 384 | Creating config file /etc/php5/fpm/php.ini with new version 385 | php5_invoke: Enable module pdo for fpm SAPI 386 | php5_invoke: Enable module pdo_mysql for fpm SAPI 387 | php5_invoke: Enable module opcache for fpm SAPI 388 | php5_invoke: Enable module json for fpm SAPI 389 | php5_invoke: Enable module mysql for fpm SAPI 390 | php5_invoke: Enable module mysqli for fpm SAPI 391 | invoke-rc.d: policy-rc.d denied execution of start. 392 | Processing triggers for libc-bin (2.19-0ubuntu6.3) ... 393 | Processing triggers for ureadahead (0.100.0-16) ... 394 | ``` 395 | -------------------------------------------------------------------------------- /css/vendor.css: -------------------------------------------------------------------------------- 1 | @media screen and (min-width: 768px) { 2 | body { 3 | width: 748px; 4 | margin: 40px auto; 5 | } 6 | } 7 | 8 | 9 | /*! 10 | * Mifa v0.2.0 11 | * https://github.com/phodal/mifa#readme 12 | * 13 | * Copyright (c) 2018 Phodal Huang 14 | * Licensed under the MIT license 15 | */ 16 | 17 | .color-primary { 18 | color: #384452; 19 | background-color: #384452; 20 | } 21 | 22 | .color-grey { 23 | color: #d1d8df; 24 | background-color: #d1d8df; 25 | } 26 | 27 | .color-green { 28 | color: #1abc9c; 29 | background-color: #1abc9c; 30 | } 31 | 32 | .color-dark-grey { 33 | color: #5e6772; 34 | background-color: #5e6772; 35 | } 36 | 37 | .color-blue { 38 | color: #23B7F3; 39 | background-color: #23B7F3; 40 | } 41 | 42 | .color-code-grey { 43 | color: #eef1f5; 44 | background-color: #eef1f5; 45 | } 46 | 47 | .color-red { 48 | color: #f53d3d; 49 | background-color: #f53d3d; 50 | } 51 | 52 | .color-yellow { 53 | color: #ffff3a; 54 | background-color: #ffff3a; 55 | } 56 | 57 | .color-light-grey { 58 | color: #fdfdfd; 59 | background-color: #fdfdfd; 60 | } 61 | 62 | *, 63 | *:after, 64 | *:before { 65 | box-sizing: inherit; 66 | } 67 | 68 | html { 69 | box-sizing: border-box; 70 | font-size: 62.5%; 71 | } 72 | 73 | body { 74 | color: #384452; 75 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", SimSun, sans-serif; 76 | font-size: 1.6em; 77 | font-weight: 300; 78 | letter-spacing: .01em; 79 | line-height: 1.6; 80 | } 81 | 82 | blockquote { 83 | border-left: 0.3rem solid #1abc9c; 84 | margin-left: 0; 85 | margin-right: 0; 86 | padding: 1rem 1.5rem; 87 | } 88 | 89 | blockquote *:last-child { 90 | margin-bottom: 0; 91 | } 92 | 93 | q:before { 94 | color: #1abc9c; 95 | content: open-quote; 96 | font-size: 4em; 97 | line-height: 0.1em; 98 | margin-right: 0.25em; 99 | vertical-align: -0.4em; 100 | } 101 | 102 | q:after { 103 | content: none; 104 | } 105 | 106 | .button, 107 | button, 108 | input[type='button'], 109 | input[type='reset'], 110 | input[type='submit'] { 111 | background-color: #384452; 112 | border: 0.1rem solid #384452; 113 | border-radius: .4rem; 114 | color: #fff; 115 | cursor: pointer; 116 | display: inline-block; 117 | font-size: 1.1rem; 118 | font-weight: 700; 119 | height: 3.8rem; 120 | letter-spacing: .1rem; 121 | line-height: 3.8rem; 122 | padding: 0 3.0rem; 123 | text-align: center; 124 | text-decoration: none; 125 | text-transform: uppercase; 126 | white-space: nowrap; 127 | } 128 | 129 | .button:focus, .button:hover, 130 | button:focus, 131 | button:hover, 132 | input[type='button']:focus, 133 | input[type='button']:hover, 134 | input[type='reset']:focus, 135 | input[type='reset']:hover, 136 | input[type='submit']:focus, 137 | input[type='submit']:hover { 138 | background-color: #1abc9c; 139 | border-color: #1abc9c; 140 | color: #fff; 141 | outline: 0; 142 | } 143 | 144 | .button[disabled], 145 | button[disabled], 146 | input[type='button'][disabled], 147 | input[type='reset'][disabled], 148 | input[type='submit'][disabled] { 149 | cursor: default; 150 | opacity: .5; 151 | } 152 | 153 | .button[disabled]:focus, .button[disabled]:hover, 154 | button[disabled]:focus, 155 | button[disabled]:hover, 156 | input[type='button'][disabled]:focus, 157 | input[type='button'][disabled]:hover, 158 | input[type='reset'][disabled]:focus, 159 | input[type='reset'][disabled]:hover, 160 | input[type='submit'][disabled]:focus, 161 | input[type='submit'][disabled]:hover { 162 | background-color: #384452; 163 | border-color: #384452; 164 | } 165 | 166 | .button.button-outline, 167 | button.button-outline, 168 | input[type='button'].button-outline, 169 | input[type='reset'].button-outline, 170 | input[type='submit'].button-outline { 171 | background-color: transparent; 172 | color: #384452; 173 | } 174 | 175 | .button.button-outline:focus, .button.button-outline:hover, 176 | button.button-outline:focus, 177 | button.button-outline:hover, 178 | input[type='button'].button-outline:focus, 179 | input[type='button'].button-outline:hover, 180 | input[type='reset'].button-outline:focus, 181 | input[type='reset'].button-outline:hover, 182 | input[type='submit'].button-outline:focus, 183 | input[type='submit'].button-outline:hover { 184 | background-color: transparent; 185 | border-color: #1abc9c; 186 | color: #1abc9c; 187 | } 188 | 189 | .button.button-outline[disabled]:focus, .button.button-outline[disabled]:hover, 190 | button.button-outline[disabled]:focus, 191 | button.button-outline[disabled]:hover, 192 | input[type='button'].button-outline[disabled]:focus, 193 | input[type='button'].button-outline[disabled]:hover, 194 | input[type='reset'].button-outline[disabled]:focus, 195 | input[type='reset'].button-outline[disabled]:hover, 196 | input[type='submit'].button-outline[disabled]:focus, 197 | input[type='submit'].button-outline[disabled]:hover { 198 | border-color: inherit; 199 | color: #384452; 200 | } 201 | 202 | .button.button-clear, 203 | button.button-clear, 204 | input[type='button'].button-clear, 205 | input[type='reset'].button-clear, 206 | input[type='submit'].button-clear { 207 | background-color: transparent; 208 | border-color: transparent; 209 | color: #384452; 210 | } 211 | 212 | .button.button-clear:focus, .button.button-clear:hover, 213 | button.button-clear:focus, 214 | button.button-clear:hover, 215 | input[type='button'].button-clear:focus, 216 | input[type='button'].button-clear:hover, 217 | input[type='reset'].button-clear:focus, 218 | input[type='reset'].button-clear:hover, 219 | input[type='submit'].button-clear:focus, 220 | input[type='submit'].button-clear:hover { 221 | background-color: transparent; 222 | border-color: transparent; 223 | color: #1abc9c; 224 | } 225 | 226 | .button.button-clear[disabled]:focus, .button.button-clear[disabled]:hover, 227 | button.button-clear[disabled]:focus, 228 | button.button-clear[disabled]:hover, 229 | input[type='button'].button-clear[disabled]:focus, 230 | input[type='button'].button-clear[disabled]:hover, 231 | input[type='reset'].button-clear[disabled]:focus, 232 | input[type='reset'].button-clear[disabled]:hover, 233 | input[type='submit'].button-clear[disabled]:focus, 234 | input[type='submit'].button-clear[disabled]:hover { 235 | color: #384452; 236 | } 237 | 238 | code { 239 | background: #eef1f5; 240 | border-radius: .4rem; 241 | font-size: 86%; 242 | margin: 0 .2rem; 243 | padding: .2rem .5rem; 244 | white-space: nowrap; 245 | } 246 | 247 | pre { 248 | background: #eef1f5; 249 | border-left: 0.3rem solid #1abc9c; 250 | overflow-y: hidden; 251 | } 252 | 253 | pre > code { 254 | border-radius: 0; 255 | display: block; 256 | padding: 1rem 1.5rem; 257 | white-space: pre; 258 | } 259 | 260 | hr { 261 | border: 0; 262 | border-top: 0.1rem solid #384452; 263 | margin: 3.0rem 0; 264 | } 265 | 266 | input[type='email'], 267 | input[type='number'], 268 | input[type='password'], 269 | input[type='search'], 270 | input[type='tel'], 271 | input[type='text'], 272 | input[type='url'], 273 | input:not([type]), 274 | textarea, 275 | select { 276 | -webkit-appearance: none; 277 | -moz-appearance: none; 278 | appearance: none; 279 | background-color: transparent; 280 | border: 0.1rem solid #d1d8df; 281 | border-radius: .4rem; 282 | box-shadow: none; 283 | box-sizing: inherit; 284 | height: 3.8rem; 285 | padding: .6rem 1.0rem; 286 | width: 100%; 287 | } 288 | 289 | input[type='email']:focus, 290 | input[type='number']:focus, 291 | input[type='password']:focus, 292 | input[type='search']:focus, 293 | input[type='tel']:focus, 294 | input[type='text']:focus, 295 | input[type='url']:focus, 296 | input:not([type]):focus, 297 | textarea:focus, 298 | select:focus { 299 | border-color: #1abc9c; 300 | outline: 0; 301 | } 302 | 303 | select { 304 | background: url('data:image/svg+xml;utf8,') center right no-repeat; 305 | padding-right: 3.0rem; 306 | } 307 | 308 | select:focus { 309 | background-image: url('data:image/svg+xml;utf8,'); 310 | } 311 | 312 | textarea { 313 | min-height: 6.5rem; 314 | } 315 | 316 | label, 317 | legend { 318 | display: block; 319 | font-size: 1.6rem; 320 | font-weight: 700; 321 | margin-bottom: .5rem; 322 | } 323 | 324 | fieldset { 325 | border-width: 0; 326 | padding: 0; 327 | } 328 | 329 | input[type='checkbox'], 330 | input[type='radio'] { 331 | display: inline; 332 | } 333 | 334 | .label-inline { 335 | display: inline-block; 336 | font-weight: normal; 337 | margin-left: .5rem; 338 | } 339 | 340 | .container { 341 | margin: 0 auto; 342 | max-width: 112.0rem; 343 | padding: 0 2.0rem; 344 | position: relative; 345 | width: 100%; 346 | } 347 | 348 | .row { 349 | display: flex; 350 | flex-direction: column; 351 | padding: 0; 352 | width: 100%; 353 | } 354 | 355 | .row.row-no-padding { 356 | padding: 0; 357 | } 358 | 359 | .row.row-no-padding > .column { 360 | padding: 0; 361 | } 362 | 363 | .row.row-wrap { 364 | flex-wrap: wrap; 365 | } 366 | 367 | .row.row-top { 368 | align-items: flex-start; 369 | } 370 | 371 | .row.row-bottom { 372 | align-items: flex-end; 373 | } 374 | 375 | .row.row-center { 376 | align-items: center; 377 | } 378 | 379 | .row.row-stretch { 380 | align-items: stretch; 381 | } 382 | 383 | .row.row-baseline { 384 | align-items: baseline; 385 | } 386 | 387 | .row .column { 388 | display: block; 389 | flex: 1 1 auto; 390 | margin-left: 0; 391 | max-width: 100%; 392 | width: 100%; 393 | } 394 | 395 | .row .column.column-offset-10 { 396 | margin-left: 10%; 397 | } 398 | 399 | .row .column.column-offset-20 { 400 | margin-left: 20%; 401 | } 402 | 403 | .row .column.column-offset-25 { 404 | margin-left: 25%; 405 | } 406 | 407 | .row .column.column-offset-33, .row .column.column-offset-34 { 408 | margin-left: 33.3333%; 409 | } 410 | 411 | .row .column.column-offset-50 { 412 | margin-left: 50%; 413 | } 414 | 415 | .row .column.column-offset-66, .row .column.column-offset-67 { 416 | margin-left: 66.6666%; 417 | } 418 | 419 | .row .column.column-offset-75 { 420 | margin-left: 75%; 421 | } 422 | 423 | .row .column.column-offset-80 { 424 | margin-left: 80%; 425 | } 426 | 427 | .row .column.column-offset-90 { 428 | margin-left: 90%; 429 | } 430 | 431 | .row .column.column-10 { 432 | flex: 0 0 10%; 433 | max-width: 10%; 434 | } 435 | 436 | .row .column.column-20 { 437 | flex: 0 0 20%; 438 | max-width: 20%; 439 | } 440 | 441 | .row .column.column-25 { 442 | flex: 0 0 25%; 443 | max-width: 25%; 444 | } 445 | 446 | .row .column.column-33, .row .column.column-34 { 447 | flex: 0 0 33.3333%; 448 | max-width: 33.3333%; 449 | } 450 | 451 | .row .column.column-40 { 452 | flex: 0 0 40%; 453 | max-width: 40%; 454 | } 455 | 456 | .row .column.column-50 { 457 | flex: 0 0 50%; 458 | max-width: 50%; 459 | } 460 | 461 | .row .column.column-60 { 462 | flex: 0 0 60%; 463 | max-width: 60%; 464 | } 465 | 466 | .row .column.column-66, .row .column.column-67 { 467 | flex: 0 0 66.6666%; 468 | max-width: 66.6666%; 469 | } 470 | 471 | .row .column.column-75 { 472 | flex: 0 0 75%; 473 | max-width: 75%; 474 | } 475 | 476 | .row .column.column-80 { 477 | flex: 0 0 80%; 478 | max-width: 80%; 479 | } 480 | 481 | .row .column.column-90 { 482 | flex: 0 0 90%; 483 | max-width: 90%; 484 | } 485 | 486 | .row .column .column-top { 487 | align-self: flex-start; 488 | } 489 | 490 | .row .column .column-bottom { 491 | align-self: flex-end; 492 | } 493 | 494 | .row .column .column-center { 495 | -ms-grid-row-align: center; 496 | align-self: center; 497 | } 498 | 499 | @media (min-width: 40rem) { 500 | .row { 501 | flex-direction: row; 502 | margin-left: -1.0rem; 503 | width: calc(100% + 2.0rem); 504 | } 505 | .row .column { 506 | margin-bottom: inherit; 507 | padding: 0 1.0rem; 508 | } 509 | } 510 | 511 | img { 512 | max-width: 100%; 513 | } 514 | 515 | a { 516 | color: #1abc9c; 517 | text-decoration: none; 518 | } 519 | 520 | a:focus, a:hover { 521 | color: #23B7F3; 522 | } 523 | 524 | dl, 525 | ol, 526 | ul { 527 | list-style: none; 528 | margin-top: 0; 529 | padding-left: 0; 530 | } 531 | 532 | dl dl, 533 | dl ol, 534 | dl ul, 535 | ol dl, 536 | ol ol, 537 | ol ul, 538 | ul dl, 539 | ul ol, 540 | ul ul { 541 | font-size: 90%; 542 | margin: 1.5rem 0 1.5rem 3.0rem; 543 | } 544 | 545 | ol { 546 | list-style: decimal inside; 547 | } 548 | 549 | ul { 550 | list-style: circle inside; 551 | } 552 | 553 | .button, 554 | button, 555 | dd, 556 | dt, 557 | li { 558 | margin-bottom: 1.0rem; 559 | } 560 | 561 | fieldset, 562 | input, 563 | select, 564 | textarea { 565 | margin-bottom: 1.5rem; 566 | } 567 | 568 | blockquote, 569 | dl, 570 | figure, 571 | form, 572 | ol, 573 | p, 574 | pre, 575 | table, 576 | ul { 577 | margin-bottom: 2.5rem; 578 | } 579 | 580 | table { 581 | border-spacing: 0; 582 | width: 100%; 583 | } 584 | 585 | table thead th, 586 | thead th { 587 | border-top: 0.1rem solid #d1d8df; 588 | background: #fdfdfd; 589 | } 590 | 591 | tbody tr:nth-child(even) { 592 | background: #fdfdfd; 593 | } 594 | 595 | tbody tr:nth-child(odd) { 596 | background: #eef1f5; 597 | } 598 | 599 | td, 600 | th { 601 | border-bottom: 0.1rem solid #d1d8df; 602 | padding: 1.2rem 1.5rem; 603 | text-align: left; 604 | } 605 | 606 | td:first-child, 607 | th:first-child { 608 | padding-left: 0; 609 | } 610 | 611 | td:last-child, 612 | th:last-child { 613 | padding-right: 0; 614 | } 615 | 616 | u { 617 | text-decoration: none; 618 | border-bottom: 1px dashed; 619 | } 620 | 621 | a { 622 | text-decoration: none; 623 | } 624 | 625 | u { 626 | background: #ffff3a; 627 | } 628 | 629 | b, 630 | strong { 631 | font-weight: bold; 632 | } 633 | 634 | p { 635 | margin-top: 0; 636 | } 637 | 638 | h1, 639 | h2, 640 | h3, 641 | h4, 642 | h5, 643 | h6 { 644 | font-weight: 300; 645 | letter-spacing: -.1rem; 646 | margin-bottom: 2.0rem; 647 | margin-top: 0; 648 | } 649 | 650 | h1 { 651 | font-size: 4.0rem; 652 | line-height: 1.2; 653 | } 654 | 655 | h2 { 656 | font-size: 3.2rem; 657 | line-height: 1.25; 658 | } 659 | 660 | h3 { 661 | font-size: 2.8rem; 662 | line-height: 1.3; 663 | } 664 | 665 | h4 { 666 | font-size: 2.4rem; 667 | letter-spacing: -.08rem; 668 | line-height: 1.35; 669 | } 670 | 671 | h5 { 672 | font-size: 2.0rem; 673 | letter-spacing: -.05rem; 674 | line-height: 1.5; 675 | } 676 | 677 | h6 { 678 | font-size: 1.6rem; 679 | letter-spacing: 0; 680 | line-height: 1.4; 681 | } 682 | 683 | .clearfix:after { 684 | clear: both; 685 | content: ' '; 686 | display: table; 687 | } 688 | 689 | .float-left { 690 | float: left; 691 | } 692 | 693 | .float-right { 694 | float: right; 695 | } 696 | -------------------------------------------------------------------------------- /src/3.1.coap.md: -------------------------------------------------------------------------------- 1 | #RESTful的CoAP协议 2 | 3 | ##CoAP: 嵌入式系统的REST 4 | 5 | 引自维基百科上的介绍,用的是谷歌翻译。。。 6 | 7 | > 受约束的应用协议(COAP)是一种软件协议旨在以非常简单的电子设备,使他们能够在互联网上进行交互式通信中使用。它特别针对小型低功率传感器,开关,阀门和需要被控制或监督远程,通过标准的Internet网络类似的组件。 COAP是一个应用层协议,该协议是用于在资源受限的网络连接设备,例如无线传感器网络节点使用。 COAP被设计为容易地转换为HTTP与Web简化集成,同时也能满足特殊的要求,例如多播支持,非常低的开销,和简单性。多播,低开销,以及简单性是因特网极其重要物联网(IOT)和机器对机器(M2M)设备,这往往是积重难返,有太多的内存和电源,比传统的互联网设备有。因此,效率是非常重要的。 COAP可以在支持UDP或UDP的模拟大多数设备上运行。 8 | 9 | 简单地来说,CoAP是简化了HTTP协议的RESTful API,因而也只提供了REST的四个方法,即PUT,GET,POST和DELETE。对于微小的资源受限,在资源受限的通信的IP的网络,HTTP不是一种可行的选择。它占用了太多的资源和太多的带宽。而对于物联网这种嵌入式设备来说,关于资源与带宽,是我们需要优先考虑的内容。 10 | 11 | - CoAP采用了二进制报头,而不是文本报头(text header) 12 | - CoAP降低了头的可用选项的数量。 13 | - CoAP减少了一些HTTP的方法 14 | - CoAP可以支持检测装置 15 | 16 | ##CoAP 命令行工具 17 | 18 | 为了测试测试我们的代码是否是正确工作,我们需要一个CoAP的命令行工具。目前有两个不错的工具可以使用。 19 | 20 | - CoAP-cli,一个基于NodeJS的CoAP命令行工具,其核心是基于Node-CoAP库。 21 | - libcooap,一个用C写的CoAP命令行工具。 22 | - FireFox Copper, 一个Firefox的插件。 23 | 24 | ###Node CoAP CLI 25 | 26 | 安装命令如下 27 | 28 | ```bash 29 | npm install coap-cli -g 30 | ``` 31 | 32 | ####CoAP命令行 33 | 34 | 在coap-cli中,一共有四个方法。分别表示REST的四种不同的方式: 35 | 36 | ```bash 37 | Commands: 38 | 39 | get performs a GET request 40 | put performs a PUT request 41 | post performs a POST request 42 | delete performs a DELETE request 43 | ``` 44 | 45 | 在这里,我们用[coap://vs0.inf.ethz.ch/](coap://vs0.inf.ethz.ch/)来作一个简单的测试 46 | 47 | ```bash 48 | coap get coap://vs0.inf.ethz.ch/ 49 | (2.05) ************************************************************ 50 | I-D 51 | ``` 52 | 53 | 测试一下现在的最小的物联网系统CoAP版 54 | 55 | ```bash 56 | coap get coap://iot-coap.phodal.com/id/1 57 | (2.05) [{"id":1,"value":"is id 1","sensors1":19,"sensors2":20}] 58 | ``` 59 | 60 | ###libcoap 61 | 62 | ####mac os libcoap安装 63 | 64 | Mac OS下可以直接用 65 | 66 | ```bash 67 | brew install libcoap 68 | ``` 69 | 70 | ####Ubuntu libcoap安装 71 | 72 | Ubuntu GNU/Linux下 73 | 74 | ####Windows libcoap安装 75 | 76 | Windows 下 77 | 78 | 安装完libcoap,我们可以直接用自带的两个命令 79 | 80 | ```bash 81 | coap-client 82 | coap-server 83 | ``` 84 | 85 | 1.用coap-server启一个CoAP服务 86 | 87 | ```bash 88 | coap-server 89 | ``` 90 | 91 | 2.客户端获取数据 92 | 93 | ```bash 94 | coap-client -m get coap://localhost 95 | ``` 96 | 97 | 返回结果 98 | 99 | ```bash 100 | v:1 t:0 tkl:0 c:1 id:37109 101 | This is a test server made with libcoap (see http://libcoap.sf.net) 102 | Copyright (C) 2010--2013 Olaf Bergmann 103 | ``` 104 | 105 | ###Firefox Copper 106 | 107 | 为了能访问[coap://localhost/](coap://localhost/),于是我们便需要安装一个Firefox并安装一个名为Copper的插件。 108 | 109 | 1. 下载地址: [https://addons.mozilla.org/en-US/firefox/addon/copper-270430/](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/) 110 | 111 | 2. 作为测试我们同样可以访问 [coap://vs0.inf.ethz.ch:5683/](coap://vs0.inf.ethz.ch:5683/) 112 | 113 | ##CoAP Hello,World 114 | 115 | 接着我们便开始试试做一个简单的CoAP协议的应用: 116 | 117 | 这里用到的是一个Nodejs的扩展Node-CoAP 118 | 119 | > node-coap is a client and server library for CoAP modelled after the http module. 120 | 121 | Node-CoAP是一个客户端和服务端的库用于CoAP的模块建模。创建一个package.json文件,添加这个库 122 | 123 | ```javascript 124 | { 125 | "dependencies":{ 126 | "coap": "0.7.2" 127 | } 128 | } 129 | ``` 130 | 131 | 接着执行 132 | 133 | ```bash 134 | npm install 135 | ``` 136 | 137 | 就可以安装好这个库。如果遇到权限问题,请用 138 | 139 | ```bash 140 | sudo npm install 141 | ``` 142 | 143 | 接着,创建这样一个app.js 144 | 145 | ```javascript 146 | const coap = require('coap') 147 | , server = coap.createServer() 148 | 149 | server.on('request', function(req, res) { 150 | res.end('Hello ' + req.url.split('/')[1] + '\n') 151 | }) 152 | 153 | server.listen(function() { 154 | console.log('server started') 155 | }) 156 | ``` 157 | 158 | 执行 159 | 160 | ```bash 161 | node app.js 162 | ``` 163 | 164 | 便可以在浏览器上访问了,因为现在什么也没有,所以什么也不会返回。 165 | 166 | 接着下来再创建一个client端的js,并运行之 167 | 168 | ```javascript 169 | const coap = require('coap') 170 | , req = coap.request('coap://localhost/World') 171 | 172 | req.on('response', function(res) { 173 | res.pipe(process.stdout) 174 | }) 175 | 176 | req.end() 177 | ``` 178 | 179 | 就可以在console上输出 180 | 181 | ```bash 182 | Hello World 183 | ``` 184 | 185 | 也就达到了我们的目的,用CoAP协议创建一个服务,接着我们应该用它创建更多的东西,如产生JSON数据,以及RESTful。和HTTP版的最小物联网系统一样,CoAP版的最小物联网系统也是要返回JSON的。 186 | 187 | ##CoAP 数据库查询 188 | 189 | ###Node Module 190 | 191 | 这说里NodeJS Module的意义是因为我们需要在别的地方引用到db_helper这个库,也就是下一小节要的讲的内容。 192 | 193 | 这样我们就可以在server.js类似于这样去引用这个js库。 194 | 195 | ```javascript 196 | var DBHelper = require('./db_helper.js'); 197 | DBHelper.initDB(); 198 | ``` 199 | 200 | 而这样调用的前提是我们需要去声明这样的module,为了方便地导出函数功能调用。 201 | 202 | ```javascript 203 | function DBHelper(){ 204 | } 205 | DBHelper.initDB = function(){}; 206 | module.exports = DBHelper; 207 | ``` 208 | 209 | ###Node-Sqlite3 210 | 211 | 这次我们用的是SQLite3(你可以用MySQL,出于安全考虑用SQLite3,SQLite3产生的是一个文件)。一个简单的initDB函数 212 | 213 | ```javascript 214 | var db = new sqlite3.Database(config["db_name"]); 215 | var create_table = 'create table if not exists basic (' + config["db_table"] + ');'; 216 | 217 | db.serialize(function() { 218 | db.run(create_table); 219 | _.each(config["init_table"], function(insert_data) { 220 | db.run(insert_data); 221 | }); 222 | }); 223 | db.close(); 224 | ``` 225 | 226 | 首先从配置中读取db_name,接着创建table,然后调用underscore的each方法,创建几个数据。配置如下所示 227 | 228 | ```javascript 229 | config = { 230 | "db_name": "iot.db", 231 | "db_table": "id integer primary key, value text, sensors1 float, sensors2 float", 232 | "init_table":[ 233 | "insert or replace into basic (id,value,sensors1,sensors2) VALUES (1, 'is id 1', 19, 20);", 234 | "insert or replace into basic (id,value,sensors1,sensors2) VALUES (2, 'is id 2', 20, 21);" 235 | ], 236 | "query_table":"select * from basic;" 237 | }; 238 | ``` 239 | 240 | 而之前所提到的url查询所做的事情便是 241 | 242 | ```javascript 243 | DBHelper.urlQueryData = function (url, callback) { 244 | var db = new sqlite3.Database("iot.db"); 245 | var result = []; 246 | console.log("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2]); 247 | db.all("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2], function(err, rows) { 248 | db.close(); 249 | callback(JSON.stringify(rows)); 250 | }); 251 | }; 252 | ``` 253 | 254 | 将URL传进来,便解析这个参数,接着再放到数据库中查询,再回调回结果。这样我们就可以构成之前所说的查询功能,而我们所谓的post功能似乎也可以用同样的方法加进去。 255 | 256 | ###查询数据 257 | 258 | 简单地记录一下在IoT-CoAP中一次获取数据地过程。 259 | 260 | 先看看在示例中的Get.js的代码,这关乎在后面server端的代码。 261 | 262 | ```javascript 263 | const coap = require('coap') 264 | ,requestURI = 'coap://localhost/' 265 | ,url = require('url').parse(requestURI + 'id/1/') 266 | ,req = coap.request(url) 267 | ,bl = require('bl'); 268 | 269 | req.setHeader("Accept", "application/json"); 270 | req.on('response', function(res) { 271 | res.pipe(bl(function(err, data) { 272 | var json = JSON.parse(data); 273 | console.log(json); 274 | })); 275 | 276 | }); 277 | req.end(); 278 | ``` 279 | 280 | const定义数据的方法,和我们在其他语言中有点像。只是这的const主要是为了程序的健壮型,减少程序出错,当然这不是javascript的用法。 281 | 282 | 我们构建了一个请求的URL 283 | 284 | ```bash 285 | coap://localhost/id/1/ 286 | ``` 287 | 288 | 我们对我们的请求添加了一个Header,内容是Accept,值是'application/json'也就是JSON格式。接着,便是等待请求回来,再处理返回的内容。 289 | 290 | **判断请求的方法** 291 | 292 | 在这里先把一些无关的代码删除掉,并保证其能工作,so,下面就是简要的逻辑代码。 293 | 294 | ```javascript 295 | var coap = require('coap'); 296 | var server = coap.createServer({}); 297 | var request_handler = require('./request_handler.js'); 298 | 299 | server.on('request', function(req, res) { 300 | switch(req.method){ 301 | case "GET": request_handler.getHandler(req, res); 302 | break; 303 | } 304 | }); 305 | 306 | server.listen(function() { 307 | console.log('server started'); 308 | }); 309 | ``` 310 | 311 | 创建一个CoAP服务,判断req.method,也就是请求的方法,如果是GET的话,就调用request_handler.getHandler(req, res)。而在getHandler里,判断了下请求的Accept 312 | 313 | ```javascript 314 | request_helper.getHandler = function(req, res) { 315 | switch (req.headers['Accept']) { 316 | case "application/json": 317 | qh.returnJSON(req, res); 318 | break; 319 | case "application/xml": 320 | qh.returnXML(req, res); 321 | break; 322 | } 323 | }; 324 | ``` 325 | 326 | 如果是json刚调用returnJSON, 327 | 328 | **Database与回调** 329 | 330 | 而这里为了处理回调函数刚分为了两部分 331 | 332 | ```javascript 333 | query_helper.returnJSON = function(req, res) { 334 | DBHelper.urlQueryData(req.url, function (result) { 335 | QueryData.returnJSON(result, res); 336 | }); 337 | }; 338 | ``` 339 | 340 | 而这里只是调用了 341 | 342 | ```javascript 343 | DBHelper.urlQueryData = function (url, callback) { 344 | var db = new sqlite3.Database(config["db_name"]); 345 | console.log("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2]); 346 | db.all("SELECT * FROM basic where " + url.split('/')[1] + "=" + url.split('/')[2], function(err, rows) { 347 | db.close(); 348 | callback(JSON.stringify(rows)); 349 | }); 350 | }; 351 | ``` 352 | 353 | 这里调用了node sqlite3去查询对应id的数据,用回调处理了数据无法到外部的问题,而上面的returnJSON则只是返回最后的结果,code以及其他的内容。 354 | 355 | ```javascript 356 | QueryData.returnJSON = function(result, res) { 357 | if (result.length == 2) { 358 | res.code = '4.04'; 359 | res.end(JSON.stringify({ 360 | error: "Not Found" 361 | })); 362 | } else { 363 | res.code = '2.05'; 364 | res.end(result); 365 | } 366 | }; 367 | ``` 368 | 369 | 当resulst的结果为空时,返回一个404,因为没有数据。这样我们就构成了整个的链,再一步步返回结果。 370 | 371 | 在[IoT-CoAP](https://github.com/phodal/iot-coap)中我们使用到了一个Block2的东西,于是便整理相关的一些资料,作一个简单的介绍,以及在代码中的使用。 372 | 373 | ##CoAP Block 374 | 375 | CoAP是一个RESTful传输协议用于受限设备的节点和网络。基本的CoAP消息是一个不错的选择对于小型载荷如 376 | 377 | - 温度传感器 378 | - 灯光开关 379 | - 楼宇自动化设备 380 | 381 | 然而,有时我们的应用需要传输更大的有效载荷,如——更新固件。与HTTP,TCP做繁重工作将大型有效载荷分成多个数据包,并确保他们所有到达并以正确的顺序被处理。 382 | 383 | CoAP是同UDP与DLTS一样是基于数据报传输的,这限制了资源表示(resource representation)的最大大小,使得传输不需要太多的分割。虽然UDP支持通过IP分片传输更大的有效载荷,且仅限于64KiB,更重要的是,并没有真正很好地约束应用和网络。 384 | 385 | 而不是依赖于IP分片,这种规范基本COAP了对“块”选项,用于传输信息从多个资源区块的请求 - 响应对。在许多重要的情况下,阻止使服务器能够真正无状态:服务器可以处理每块分开传输,而无需建立连接以前的数据块传输的其他服务器端内存。 386 | 387 | 综上所述,块(Block)选项提供了传送一个最小的在分块的方式更大的陈述。 388 | 389 | ###CoAP POST 390 | 391 | 看看在IoT CoAP中的post示例。 392 | 393 | ```javascript 394 | const coap = require('coap') 395 | ,request = coap.request 396 | ,bl = require('bl') 397 | ,req = request({hostname: 'localhost',port:5683,pathname: '',method: 'POST'}); 398 | 399 | req.setOption('Block2', [new Buffer('1'),new Buffer("'must'"), new Buffer('23'), new Buffer('12')]); 400 | req.setHeader("Accept", "application/json"); 401 | req.on('response', function(res) { 402 | res.pipe(bl(function(err, data) { 403 | console.log(data); 404 | process.exit(0); 405 | })); 406 | 407 | }); 408 | 409 | req.end(); 410 | ``` 411 | 412 | Block2中一共有四个数据,相应的数据结果应该是 413 | 414 | ```javascript 415 | { name: 'Block2', value: } 416 | { name: 'Block2', value: } 417 | { name: 'Block2', value: } 418 | { name: 'Block2', value: } 419 | ``` 420 | 421 | 这是没有解析的Block2,简单地可以用 422 | 423 | ```javascript 424 | _.values(e).toString() 425 | ``` 426 | 将结果转换为 427 | 428 | Block2,1 429 | Block2,'must' 430 | Block2,23 431 | Block2,12 432 | 433 | 接着按","分开, 434 | 435 | ```javascript 436 | _.values(e).toString().split(',')[1] 437 | ``` 438 | 439 | 就有 440 | 441 | ```bash 442 | [ '1', '\'must\'', '23', '12' ] 443 | ``` 444 | 445 | 便可以很愉快地将其post到数据库中了, 446 | 447 | 在做IoT-CoAP的过程中只支持JSON,查阅CoAP的草稿时发现支持了诸多的Content Types。 448 | 449 | ###CoAP Content Types 450 | 451 | 以下文字来自谷歌翻译: 452 | 453 | > 互联网媒体类型是通过HTTP字符串标识,如“application/xml”。该字符串是由一个顶层的类型“applicaion”和子类型的“XML”。为了尽量减少使用这些类型的媒体类型来表示的开销消息有效载荷,COAP定义一个标识符编码方案互联网媒体类型的子集。预计这桌将可扩展标识符的值的IANA维护。内容类型选项被格式化为一个8位无符号整数。初始映射到一个合适的互联网媒体类型标识符表所示。复合型高层次类型(multipart和不支持消息)。标识符值是从201-255保留的特定于供应商的,应用程序特定的或实验使用和不由IANA。 454 | 455 | 下面是HTTP的标识符及类型 456 | 457 | | Internet media type | Identifier | 458 | |-----------------------------------------------------|------------| 459 | | text/plain (UTF-8) | 0 | 460 | | text/xml (UTF-8) | 1 | 461 | | text/csv (UTF-8) | 2 | 462 | | text/html (UTF-8) | 3 | 463 | | image/gif | 21 | 464 | | image/jpeg | 22 | 465 | | image/png | 23 | 466 | | image/tiff | 24 | 467 | | audio/raw | 25 | 468 | | video/raw | 26 | 469 | | application/link-format [I-D.ietf-core-link-format] | 40 | 470 | | application/xml | 41 | 471 | | application/octet-stream | 42 | 472 | | application/rdf+xml | 43 | 473 | | application/soap+xml | 44 | 474 | | application/atom+xml | 45 | 475 | | application/xmpp+xml | 46 | 476 | | application/exi | 47 | 477 | | application/x-bxml | 48 | 478 | | application/fastinfoset | 49 | 479 | | application/soap+fastinfoset | 50 | 480 | | application/json | 51 | 481 | 482 | 483 | 而在CoAP中只有简单地几个 484 | 485 | 486 | | Media type | Encoding | Id. | Reference | 487 | |------------------|----------|-------|-----------------------------| 488 | | text/plain; | - | 0 | [RFC2046][RFC3676][RFC5147] | 489 | | charset=utf-8 | | | | 490 | | application/ | - | 40 | [RFC6690] | 491 | | link-format | | | | 492 | | application/xml | - | 41 | [RFC3023] | 493 | | application/ | - | 42 | [RFC2045][RFC2046] | 494 | | octet-stream | | | | 495 | | application/exi | - | 47 | [EXIMIME] | 496 | | application/json | - | 50 | [RFC4627] | 497 | 498 | 499 | 简单地说就是: 500 | 501 | ``诸如application/json的Content Types在CoAP中应该是50``。如上表所示的结果是其对应的结果,这样的话可以减少传递的信息量。 502 | 503 | ##CoAP JSON 504 | 505 | 于是在一开始的时候首先支持的便是"application/json"这样的类型。 506 | 507 | 首先判断请求的header 508 | 509 | ```javascript 510 | request_helper.getHandler = function(req, res) { 511 | switch (req.headers['Accept']) { 512 | case "application/json": 513 | qh.returnJSON(req, res); 514 | break; 515 | case "application/xml": 516 | qh.returnXML(req, res); 517 | break; 518 | } 519 | }; 520 | ``` 521 | 522 | 再转至相应的函数处理,而判断的依据则是Accept是不是"application/json"。 523 | 524 | ```javascript 525 | registerFormat('text/plain', 0) 526 | registerFormat('application/link-format', 40) 527 | registerFormat('application/xml', 41) 528 | registerFormat('application/octet-stream', 42) 529 | registerFormat('application/exi', 47) 530 | registerFormat('application/json', 50) 531 | ``` 532 | 533 | 对应地我们需要在一发出请求的时候设置好Accept,要不就没有办法返回我们需要的结果。 534 | 535 | ```javascript 536 | req.setHeader("Accept", "application/json"); 537 | ``` 538 | 539 | **返回JSON** 540 | 541 | 在给IoT CoAP添加了JSON支持之后,变得非常有意思,至少我们可以获得我们想要的结果。在上一篇中我们介绍了一些常用的工具——[CoAP 命令行工具集](http://www.phodal.com/blog/coap-command-line-tools-set/)。 542 | 543 | **CoAP客户端代码** 544 | 545 | 开始之前我们需要有一个客户端代码,以便我们的服务端可以返回正确的数据并解析 546 | 547 | ```javascript 548 | var coap = require('coap'); 549 | var requestURI = 'coap://localhost/'; 550 | var url = require('url').parse(requestURI + 'id/1/'); 551 | console.log("Request URL: " + url.href); 552 | var req = coap.request(url); 553 | var bl = require('bl'); 554 | 555 | req.setHeader("Accept", "application/json"); 556 | req.on('response', function(res) { 557 | res.pipe(bl(function(err, data) { 558 | var json = JSON.parse(data); 559 | console.log(json); 560 | })); 561 | 562 | }); 563 | 564 | req.end(); 565 | ``` 566 | 567 | 代码有点长内容也有点多,但是核心是这句话: 568 | 569 | ```javascript 570 | req.setHeader("Accept", "application/json"); 571 | ``` 572 | 573 | 这样的话,我们只需要在我们的服务端一判断, 574 | 575 | ```javascript 576 | if(req.headers['Accept'] == 'application/json') { 577 | //do something 578 | }; 579 | ``` 580 | 581 | 这样就可以返回数据了 582 | 583 | **CoAP Server端代码** 584 | 585 | Server端的代码比较简单,判断一下 586 | 587 | ```javascript 588 | if (req.headers['Accept'] == 'application/json') { 589 | parse_url(req.url, function(result){ 590 | res.end(result); 591 | }); 592 | res.code = '2.05'; 593 | } 594 | ``` 595 | 596 | 请求的是否是JSON格式,再返回一个205,也就是Content,只是这时设计是请求一个URL返回对应的数据。如 597 | 598 | ```bash 599 | coap://localhost/id/1/ 600 | ``` 601 | 602 | 这时应该请求的是ID为1的数据,即 603 | 604 | ```javascript 605 | [ { id: 1, value: 'is id 1', sensors1: 19, sensors2: 20 }] 606 | ``` 607 | 608 | 而parse_url只是从数据库从读取相应的数据。 609 | 610 | ```javascript 611 | function parse_url(url ,callback) { 612 | var db = new sqlite3.Database(config["db_name"]); 613 | var result = []; 614 | db.all("SELECT * FROM basic;", function(err, rows) { 615 | callback(JSON.stringify(rows)); 616 | }) 617 | } 618 | ``` 619 | 620 | 并且全部都显示出来,设计得真是有点不行,不过现在已经差不多了。 621 | -------------------------------------------------------------------------------- /Licence.txt: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More_considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial 4.0 International Public 58 | License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial 4.0 International Public License ("Public 63 | License"). To the extent this Public License may be interpreted as a 64 | contract, You are granted the Licensed Rights in consideration of Your 65 | acceptance of these terms and conditions, and the Licensor grants You 66 | such rights in consideration of benefits the Licensor receives from 67 | making the Licensed Material available under these terms and 68 | conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Adapter's License means the license You apply to Your Copyright 84 | and Similar Rights in Your contributions to Adapted Material in 85 | accordance with the terms and conditions of this Public License. 86 | 87 | c. Copyright and Similar Rights means copyright and/or similar rights 88 | closely related to copyright including, without limitation, 89 | performance, broadcast, sound recording, and Sui Generis Database 90 | Rights, without regard to how the rights are labeled or 91 | categorized. For purposes of this Public License, the rights 92 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 93 | Rights. 94 | d. Effective Technological Measures means those measures that, in the 95 | absence of proper authority, may not be circumvented under laws 96 | fulfilling obligations under Article 11 of the WIPO Copyright 97 | Treaty adopted on December 20, 1996, and/or similar international 98 | agreements. 99 | 100 | e. Exceptions and Limitations means fair use, fair dealing, and/or 101 | any other exception or limitation to Copyright and Similar Rights 102 | that applies to Your use of the Licensed Material. 103 | 104 | f. Licensed Material means the artistic or literary work, database, 105 | or other material to which the Licensor applied this Public 106 | License. 107 | 108 | g. Licensed Rights means the rights granted to You subject to the 109 | terms and conditions of this Public License, which are limited to 110 | all Copyright and Similar Rights that apply to Your use of the 111 | Licensed Material and that the Licensor has authority to license. 112 | 113 | h. Licensor means the individual(s) or entity(ies) granting rights 114 | under this Public License. 115 | 116 | i. NonCommercial means not primarily intended for or directed towards 117 | commercial advantage or monetary compensation. For purposes of 118 | this Public License, the exchange of the Licensed Material for 119 | other material subject to Copyright and Similar Rights by digital 120 | file-sharing or similar means is NonCommercial provided there is 121 | no payment of monetary compensation in connection with the 122 | exchange. 123 | 124 | j. Share means to provide material to the public by any means or 125 | process that requires permission under the Licensed Rights, such 126 | as reproduction, public display, public performance, distribution, 127 | dissemination, communication, or importation, and to make material 128 | available to the public including in ways that members of the 129 | public may access the material from a place and at a time 130 | individually chosen by them. 131 | 132 | k. Sui Generis Database Rights means rights other than copyright 133 | resulting from Directive 96/9/EC of the European Parliament and of 134 | the Council of 11 March 1996 on the legal protection of databases, 135 | as amended and/or succeeded, as well as other essentially 136 | equivalent rights anywhere in the world. 137 | 138 | l. You means the individual or entity exercising the Licensed Rights 139 | under this Public License. Your has a corresponding meaning. 140 | 141 | 142 | Section 2 -- Scope. 143 | 144 | a. License grant. 145 | 146 | 1. Subject to the terms and conditions of this Public License, 147 | the Licensor hereby grants You a worldwide, royalty-free, 148 | non-sublicensable, non-exclusive, irrevocable license to 149 | exercise the Licensed Rights in the Licensed Material to: 150 | 151 | a. reproduce and Share the Licensed Material, in whole or 152 | in part, for NonCommercial purposes only; and 153 | 154 | b. produce, reproduce, and Share Adapted Material for 155 | NonCommercial purposes only. 156 | 157 | 2. Exceptions and Limitations. For the avoidance of doubt, where 158 | Exceptions and Limitations apply to Your use, this Public 159 | License does not apply, and You do not need to comply with 160 | its terms and conditions. 161 | 162 | 3. Term. The term of this Public License is specified in Section 163 | 6(a). 164 | 165 | 4. Media and formats; technical modifications allowed. The 166 | Licensor authorizes You to exercise the Licensed Rights in 167 | all media and formats whether now known or hereafter created, 168 | and to make technical modifications necessary to do so. The 169 | Licensor waives and/or agrees not to assert any right or 170 | authority to forbid You from making technical modifications 171 | necessary to exercise the Licensed Rights, including 172 | technical modifications necessary to circumvent Effective 173 | Technological Measures. For purposes of this Public License, 174 | simply making modifications authorized by this Section 2(a) 175 | (4) never produces Adapted Material. 176 | 177 | 5. Downstream recipients. 178 | 179 | a. Offer from the Licensor -- Licensed Material. Every 180 | recipient of the Licensed Material automatically 181 | receives an offer from the Licensor to exercise the 182 | Licensed Rights under the terms and conditions of this 183 | Public License. 184 | 185 | b. No downstream restrictions. You may not offer or impose 186 | any additional or different terms or conditions on, or 187 | apply any Effective Technological Measures to, the 188 | Licensed Material if doing so restricts exercise of the 189 | Licensed Rights by any recipient of the Licensed 190 | Material. 191 | 192 | 6. No endorsement. Nothing in this Public License constitutes or 193 | may be construed as permission to assert or imply that You 194 | are, or that Your use of the Licensed Material is, connected 195 | with, or sponsored, endorsed, or granted official status by, 196 | the Licensor or others designated to receive attribution as 197 | provided in Section 3(a)(1)(A)(i). 198 | 199 | b. Other rights. 200 | 201 | 1. Moral rights, such as the right of integrity, are not 202 | licensed under this Public License, nor are publicity, 203 | privacy, and/or other similar personality rights; however, to 204 | the extent possible, the Licensor waives and/or agrees not to 205 | assert any such rights held by the Licensor to the limited 206 | extent necessary to allow You to exercise the Licensed 207 | Rights, but not otherwise. 208 | 209 | 2. Patent and trademark rights are not licensed under this 210 | Public License. 211 | 212 | 3. To the extent possible, the Licensor waives any right to 213 | collect royalties from You for the exercise of the Licensed 214 | Rights, whether directly or through a collecting society 215 | under any voluntary or waivable statutory or compulsory 216 | licensing scheme. In all other cases the Licensor expressly 217 | reserves any right to collect such royalties, including when 218 | the Licensed Material is used other than for NonCommercial 219 | purposes. 220 | 221 | 222 | Section 3 -- License Conditions. 223 | 224 | Your exercise of the Licensed Rights is expressly made subject to the 225 | following conditions. 226 | 227 | a. Attribution. 228 | 229 | 1. If You Share the Licensed Material (including in modified 230 | form), You must: 231 | 232 | a. retain the following if it is supplied by the Licensor 233 | with the Licensed Material: 234 | 235 | i. identification of the creator(s) of the Licensed 236 | Material and any others designated to receive 237 | attribution, in any reasonable manner requested by 238 | the Licensor (including by pseudonym if 239 | designated); 240 | 241 | ii. a copyright notice; 242 | 243 | iii. a notice that refers to this Public License; 244 | 245 | iv. a notice that refers to the disclaimer of 246 | warranties; 247 | 248 | v. a URI or hyperlink to the Licensed Material to the 249 | extent reasonably practicable; 250 | 251 | b. indicate if You modified the Licensed Material and 252 | retain an indication of any previous modifications; and 253 | 254 | c. indicate the Licensed Material is licensed under this 255 | Public License, and include the text of, or the URI or 256 | hyperlink to, this Public License. 257 | 258 | 2. You may satisfy the conditions in Section 3(a)(1) in any 259 | reasonable manner based on the medium, means, and context in 260 | which You Share the Licensed Material. For example, it may be 261 | reasonable to satisfy the conditions by providing a URI or 262 | hyperlink to a resource that includes the required 263 | information. 264 | 265 | 3. If requested by the Licensor, You must remove any of the 266 | information required by Section 3(a)(1)(A) to the extent 267 | reasonably practicable. 268 | 269 | 4. If You Share Adapted Material You produce, the Adapter's 270 | License You apply must not prevent recipients of the Adapted 271 | Material from complying with this Public License. 272 | 273 | 274 | Section 4 -- Sui Generis Database Rights. 275 | 276 | Where the Licensed Rights include Sui Generis Database Rights that 277 | apply to Your use of the Licensed Material: 278 | 279 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 280 | to extract, reuse, reproduce, and Share all or a substantial 281 | portion of the contents of the database for NonCommercial purposes 282 | only; 283 | 284 | b. if You include all or a substantial portion of the database 285 | contents in a database in which You have Sui Generis Database 286 | Rights, then the database in which You have Sui Generis Database 287 | Rights (but not its individual contents) is Adapted Material; and 288 | 289 | c. You must comply with the conditions in Section 3(a) if You Share 290 | all or a substantial portion of the contents of the database. 291 | 292 | For the avoidance of doubt, this Section 4 supplements and does not 293 | replace Your obligations under this Public License where the Licensed 294 | Rights include other Copyright and Similar Rights. 295 | 296 | 297 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 298 | 299 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 300 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 301 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 302 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 303 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 304 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 305 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 306 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 307 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 308 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 309 | 310 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 311 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 312 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 313 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 314 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 315 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 316 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 317 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 318 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 319 | 320 | c. The disclaimer of warranties and limitation of liability provided 321 | above shall be interpreted in a manner that, to the extent 322 | possible, most closely approximates an absolute disclaimer and 323 | waiver of all liability. 324 | 325 | 326 | Section 6 -- Term and Termination. 327 | 328 | a. This Public License applies for the term of the Copyright and 329 | Similar Rights licensed here. However, if You fail to comply with 330 | this Public License, then Your rights under this Public License 331 | terminate automatically. 332 | 333 | b. Where Your right to use the Licensed Material has terminated under 334 | Section 6(a), it reinstates: 335 | 336 | 1. automatically as of the date the violation is cured, provided 337 | it is cured within 30 days of Your discovery of the 338 | violation; or 339 | 340 | 2. upon express reinstatement by the Licensor. 341 | 342 | For the avoidance of doubt, this Section 6(b) does not affect any 343 | right the Licensor may have to seek remedies for Your violations 344 | of this Public License. 345 | 346 | c. For the avoidance of doubt, the Licensor may also offer the 347 | Licensed Material under separate terms or conditions or stop 348 | distributing the Licensed Material at any time; however, doing so 349 | will not terminate this Public License. 350 | 351 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 352 | License. 353 | 354 | 355 | Section 7 -- Other Terms and Conditions. 356 | 357 | a. The Licensor shall not be bound by any additional or different 358 | terms or conditions communicated by You unless expressly agreed. 359 | 360 | b. Any arrangements, understandings, or agreements regarding the 361 | Licensed Material not stated herein are separate from and 362 | independent of the terms and conditions of this Public License. 363 | 364 | 365 | Section 8 -- Interpretation. 366 | 367 | a. For the avoidance of doubt, this Public License does not, and 368 | shall not be interpreted to, reduce, limit, restrict, or impose 369 | conditions on any use of the Licensed Material that could lawfully 370 | be made without permission under this Public License. 371 | 372 | b. To the extent possible, if any provision of this Public License is 373 | deemed unenforceable, it shall be automatically reformed to the 374 | minimum extent necessary to make it enforceable. If the provision 375 | cannot be reformed, it shall be severed from this Public License 376 | without affecting the enforceability of the remaining terms and 377 | conditions. 378 | 379 | c. No term or condition of this Public License will be waived and no 380 | failure to comply consented to unless expressly agreed to by the 381 | Licensor. 382 | 383 | d. Nothing in this Public License constitutes or may be interpreted 384 | as a limitation upon, or waiver of, any privileges and immunities 385 | that apply to the Licensor or You, including from the legal 386 | processes of any jurisdiction or authority. 387 | 388 | ======================================================================= 389 | 390 | Creative Commons is not a party to its public licenses. 391 | Notwithstanding, Creative Commons may elect to apply one of its public 392 | licenses to material it publishes and in those instances will be 393 | considered the "Licensor." Except for the limited purpose of indicating 394 | that material is shared under a Creative Commons public license or as 395 | otherwise permitted by the Creative Commons policies published at 396 | creativecommons.org/policies, Creative Commons does not authorize the 397 | use of the trademark "Creative Commons" or any other trademark or logo 398 | of Creative Commons without its prior written consent including, 399 | without limitation, in connection with any unauthorized modifications 400 | to any of its public licenses or any other arrangements, 401 | understandings, or agreements concerning use of licensed material. For 402 | the avoidance of doubt, this paragraph does not form part of the public 403 | licenses. 404 | 405 | Creative Commons may be contacted at creativecommons.org. 406 | -------------------------------------------------------------------------------- /end/iot.md: -------------------------------------------------------------------------------- 1 | # 物联网毕业设计# 2 | 3 | ##摘要 4 | 随着经济社会的日趋发展及科学技术水平的不断提高,人们对于便利生活的要求越来越高。近年来,随着物联网领域稳步、缓慢地发展,物联网建设的网络环境已经逐渐成熟。由于物联网系统是一个综合性的,包含了硬件、软件、网络等多学科交叉的系统。对于物联网的研究和开发,已经成为一个个热门的话题。 5 | 6 | 本论文中介绍了以REST服务为核心、单片机、ARM开发板而辅助的物联网系统的结构组成及工作原理,提供了相应的软件代码及硬件结构。首先研究了不同服务框架的区别,包括不同语言间开发的优势及劣势,之后重点以REST服务为核心构建系统。本设计中,单片机与ARM开发板通过串口通信的方式实现通信,相互传输所需要的数据,ARM开发板将资源传于互联网上对应的接口,接口可以在互联网上被访问。将ARM开发板获取过来的数据存储于MySQL数据,再以REST服务的方式共享数据,互联网上的其他设备便可以通过网络来访问这些设备。系统分离了软件、硬件的耦合,不仅可以方便系统开发,也可以方便由不同的硬件替换相应的组成,使之更容易理解,同时可以实现更多设备的连接,以实现真正的物联。 7 | 8 | 本论文讨论的代码在GNU/Linux系统上开发,可在不同平台上开发及调度。 9 | 10 | **关键词** : ``物联网``、``REST服务``、``RESTful`` 11 | 12 | ##Abstract 13 | With the increasing development and scientific and technological level of the economy and society continues to improve, people's lives more convenient for the required high . In recent years, the field of Internet Of Things steady , slow development , networking and building the network environment has gradually matured. Because of Internet Of Things is a comprehensive system , including hardware , software, networks, and other multi-disciplinary systems. Things for research and development, has become one hot topic . 14 | 15 | This paper described the Internet of Things system's structure and principle in REST services as the core , microcontroller and ARM development board as assisted, and provided the appropriate software code and hardware architecture . First study the differences between the services framework, including language development among different strengths and weaknesses, then focus to build REST service system as the core . In this design, microcontroller communicate with development board by serial communication, mutual transmission of the data needed , ARM development board resources on the Internet pass the corresponding interface , the interface can be accessed on the Internet. The ARM development board to get over the data stored in MySQL, then the REST service to share data , other devices on the Internet will be able to access these devices through the network. Separation of the coupling system software, hardware , and can not only facilitate the development of the system , can also be easily replaced by a composition corresponding to different hardware , to make it easier to understand , and can connect more devices to achieve real objects associated . 16 | 17 | Code discussed in this paper on the GNU / Linux system development, and scheduling can be developed on different platforms . 18 | 19 | 20 | ##绪论## 21 | 22 | ###选题背景### 23 | 24 | 随着科技的发展,计算机电子技术迅猛发展,已经成为生活中不可缺少的部分。目前人们绝大多数都是采用PC进行网络数据传送,但由于成本高,限制了应用的范围。而嵌入式系统却越来越受到人们的青睐。它采用嵌入式的微处理器,支持 25 | TCP/IP协议,它已成为网络发展新阶段的标志。 26 | 27 | 物联网是新一代信息技术的重要组成部分。其英文名称是The Internet of things。顾名思义,物联网的意思就是物物相连的互联网。这有两层意思:第一,物联网是建立在互联网之上的,是互联网的拓展和延伸;第二,其用户端扩 28 | 展和延伸到了物品与物品之间,进行信息通信和交换。物联网有如下特征: 29 | 30 | 首先,广泛应用了各种感知技术。在物联网中部署了大量的多种传感器,每个传感器都能从外界采集信息,不同类的传感器捕获的信息不同。而且获得的数据具有实时性,按照一定的规律来采集数据,不断更新数据。 31 | 32 | 其次,它是建立在互联网上的网络。物联网技术的核心和基础仍是互联网,通过各种无线和有线网络与互联网结合起来,将物体的信息准确实时地传递出去,数据传输过程中必须适应各种网络协议。 33 | 34 | 还有,物联网本身也具有一种智能处理的能力,能够智能控制物体。物联网从传感器中获得数据,然后进行分析,处理处有意义的数据,来适应不同用户的需求。 35 | 36 | ###设计内容### 37 | 设计主要是关于基于RESTful服务的网络服务构建,可采用有线网络、无线网络、手机GSM网络等与Internet相关,通过手机、电脑 、移动设备等登录到网页可实现控制家电的上的,并可实时查看诸如温度等一些信息的基本内容。 38 | 39 | 硬件设计时,采用Arduino单片机系统,作为一个基于Atmega328芯片的最小系统,Arduino可以系统代码。Arduino主要用于展示LED灯的控制,通过与RaspberryPI开发板相连来获取实时状态。Raspberry PI作为一个ARM开发板,由于其运行的是Linux系统,在软件方面有着相对于其他开发板较好的支持,在这里是作为数据传输设备以用来进行模块分离。 40 | 41 | 软件设计时,由于一个物联网系统其核心是以网络为基础的,需要优先考虑网络 42 | 方面的优化,学需要考虑数据库等的问题。 43 | 44 | 用户界面设计时,随着近来来平板、手机等移动设备的流行,在设计时不能再以 45 | 桌面程序为核心,需要考虑不用设备之间的兼容性等问题,这里便以网页为核心 46 | 作为显示。而,随着云计算技术的流行,未来的物联网系统必然也会基于云计算 47 | 技术构建。作为一个可视化的网页来说,实时的状态显示等是较为重要,同时我 48 | 们需要考虑的是用户体验。 49 | 50 | ###设计的目的及其意义### 51 | 设计以简化物联网系统为主,简化一个可扩展的最小的物联网系统,以简化系统 52 | 的逻辑为起点,为广大的用户提供一个良好的了解物联网系统方面知识的框架。 53 | 54 | 55 | ###国内外发展现状和趋势### 56 | 物联网是建立在互联网技术之上的。目前,我国物联网发展与全球同处于起步阶 57 | 段,初步具备了一定的技术、产业和应用基础,呈现出良好的发展态势。把单片 58 | 机应用系统和Internet连接也已经是一种趋势。 59 | 60 | 目前无线通信网络已经覆盖各地,是实现“物联网”必不可少的设施,可以将安置 61 | 在每个物品上的电子介质产生的数字信号通过无线网络传输出去。“云计算”技术 62 | 的运用,使数以亿计的各类物品的实时动态管理变得可能。 63 | 64 | 物联网技术的推广已经取得一定的成效。在多方面已经开始应用,如远程抄表, 65 | 电力行业,视频监控等等。以及在物流领域和医疗领域也都日趋成熟,如物品存 66 | 储及运输监测,远程医疗,个人的健康监护等。除此之外在环境监控,楼宇节能, 67 | 食品等方面也开展了广泛应用。 68 | 69 | 尽管在这些领域已经取得一些进展,但应认识到,物联网发展技术还存在一系列 70 | 制约和瓶颈。有几个方面可以表现出来:核心技术与国外差距较大,集成服务能 71 | 力不够,缺乏骨干企业,应用水平不高,信息安全存在隐患。我们国家在PC架构 72 | 领域还没有主动权,软件产品很少。目前,计算环境正在向以网络为中心发展, 73 | 有很多产品不必也windows兼容,因此,研究单片机系统接入网络,前途宽广。 74 | 75 | #系统总体设计方案# 76 | 77 | 物联网的核心也就是网络服务,而网络服务在某种意义上来说,就是需要打造一 78 | 个多平台的通信协议,在使机器、家电、设备等连上计算机网络。基本的物联 79 | 网系统,不仅能控制设备,还可以在远程查看状态。而复杂的物联网系统可以让 80 | 互联网上的设备之间实现互联与通信,也就是物联网的最终目标所在——使物体与 81 | 物体之间的交互成为可能,不需要人为去干预。 82 | 83 | 系统采用的结构是: 84 | Arduino+Raspberry Pi+Laravel+JSON+RESTful+Ajax+Python+HighCharts,其框架图如下所示 85 | 86 | 87 | [struct]: https://raw.githubusercontent.com/phodal/thesis/master/dot/struct.png "系统框架图" 88 | ![系统框架图][struct] 89 | 90 | Arduino与Raspberry Pi通过串口通信的方式实现通信,相互传输所需要的数据, 91 | Raspberry Pi将资源传于互联网上对应的接口,接口可以在互联网上被访问。 92 | Laravel框架构架于服务器之上,将Raspbery Pi获取过来的数据存储于MySQL数 93 | 据,再以REST服务的方式共享数据,互联网上的其他设备便可以通过网络来访问 94 | 这些设备。Ajax用于将后台的数据以不需要刷新的方式传递到网站前台,通过 95 | HighCharts框架显示给终端用户。 96 | 97 | ##硬件方案选择## 98 | 99 | ###单片机选择### 100 | 101 | ####Arduino#### 102 | 103 | Arduino,是一个开放源代码的单芯片微电脑,它使用了Atmel AVR单片机,采用 104 | 了基于开放源代码的软硬件平台,构建于开放源代码 simple I/O 接口板,并且 105 | 具有使用类似Java,C 语言的Processing/Wiring开发环境。 106 | 107 | Arduino开发板封装了常用的库到开发环境中,可以让用户在开发产品时,将主 108 | 要注意力放置于所需要实现的功能上,而不是开发的过程中。在为Arduino写串 109 | 口程序时,我们只需要用Serial.begin(9600)以9600的速率初始化串口,而在往 110 | 串口发送数据时,可以用Serial.write('1')的方式向串口发送字串'1'。 111 | 112 | ####51#### 113 | 114 | 单片机[^mcu],又称微控制器,是把中央处理器、存储器、定时/计数器 115 | (Timer/Counter)、各种输入输出接口等都集成在一块集成电路芯片上的微型 116 | 计算机。与应用在个人计算机中的通用型微处理器相比,它更强调自供应(不用 117 | 外接硬件)和节约成本。它的最大优点是体积小,可放在仪表内部,但存储量小, 118 | 输入输出接口简单,功能较低。 119 | 120 | 51单片机相较于Arduino开发板,不仅代码复杂,由于系统比较古老而不方便于 121 | 快速开发。 122 | 123 | [^mcu]:全称单片微型计算机(英语:Single-Chip Microcomputer) 124 | 125 | ##软件方案选择## 126 | 127 | ###数据通讯方式选择### 128 | 129 | ####REST#### 130 | 131 | REST[^rest] 从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的 132 | 应用通过URI来获取资源的表征。获得这些表征致使这些应用程序转变了其状态。 133 | 随着不断获取资源的表征,客户端应用不断地在转变着其状态,所谓表征状态转 134 | 移。 135 | 136 | [^rest]:Representational State Transfer 137 | 138 | ####SOAP#### 139 | 140 | 简单对象访问协议是交换数据的一种协议规范,使用在计算机网络Web服务中, 141 | 交换带结构信息。SOAP为了简化网页服务器从XML数据库中提取数据时,节省去 142 | 格式化页面时间,以及不同应用程序之间按照HTTP通信协议,遵从XML格式执行 143 | 资料互换,使其抽象于语言实现、平台和硬件。 144 | 145 | ###数据通信格式选择### 146 | 147 | ####JSON#### 148 | 149 | JSON[^json]是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机 150 | 器解析和生成。 它基于JavaScript Programming Language, Standard 151 | ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语 152 | 言的文本格式,但是也使用了类似于C语言家族的习惯[^cfamily]。 这些特性使 153 | JSON成为理想的数据交换语言。 154 | 155 | JSON相对于XML来说可以减少文件的大小,同时我们可以用于网站前端的数据通讯。 156 | 157 | [^json]: JavaScript Object Notation 158 | [^cfamily]: 包括C, C++, C#, Java, JavaScript, Perl, Python等 159 | 160 | 对于基于浏览器的客户端使用的web服务更倾向于使用JSON作为表述格式。 161 | 162 | ####XML#### 163 | 164 | 可扩展标记语言[^xml],是一种标记语言。标记指计算机所能理解的信息符号, 165 | 通过此种标记,计算机之间可以处理包含各种信息的文章等。如何定义这些标记, 166 | 既可以选择国际通用的标记语言,比如HTML,也可以使用像XML这样由相关人士 167 | 自由决定的标记语言,这就是语言的可扩展性。XML是从标准通用标记语言 168 | (SGML)中简化修改出来的。它主要用到的有可扩展标记语言、可扩展样式语言 169 | (XSL)、XBRL和XPath等。 170 | 171 | XML具有良好的可读性,有着较好的库支持,从Java语言到其他语言,如Linux系 172 | 统上libxml等对XML的支持比较好。 173 | 174 | [^xml]: eXtensible Markup Language,简称: XML 175 | 176 | ##网络服务方案选择## 177 | 178 | ###语言选择### 179 | 180 | **PHP Laravel** 181 | 182 | PHP [^php] 是一种开源的通用计算机脚本语言,尤其适用于网络开发并可嵌入 183 | HTML中使用。PHP的语法借鉴吸收了C语言、Java和Perl等流行计算机语言的特点, 184 | 易于一般程序员学习。PHP的主要目标是允许网络开发人员快速编写动态页面, 185 | 但PHP也被用于其他很多领域。 186 | 187 | [^php]:PHP:Hypertext Preprocessor,即超文本预处理器 188 | 189 | **Laravel** 190 | 191 | Laravel是一套简洁、优雅的PHP Web开发框架。它可以让你从面条一样杂乱的代 192 | 码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、 193 | 富于表达力。 194 | 195 | **Java Spring** 196 | 197 | **Java** 198 | 199 | Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun 200 | Microsystems公司于1995年5月推出的Java程序设计语言。Java 技术具有卓越的 201 | 通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控 202 | 制台、科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社 203 | 群。在全球云计算和移动互联网的产业环境下,Java更具备了显著优势和广阔前 204 | 景。 205 | 206 | **Spring** 207 | 208 | Spring是一个开源框架,是为了解决企业应用程序开发复杂性。Spring框架的主 209 | 要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 210 | J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只 211 | 可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单 212 | 性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 213 | 214 | 由于相较于Java在web方面没有PHP来得快速、简单、有效,同时Laravel框架在 215 | 某些方面如数据迁移、代码生成比Spring快,同时不需要依赖于开发环境,这里 216 | 以Laravel作为框架,可以利用artisan工具等的强大驱动开发。 217 | 218 | ##其它## 219 | 220 | ###数据通讯设备### 221 | 222 | **Raspeberry PI** 223 | 224 | Raspberry Pi是一款针对电脑业余爱好者、教师、小学生以及小型企业等用户的 225 | 迷你电脑,预装Linux系统,体积仅信用卡大小,搭载ARM架构处理器,运算性能 226 | 和智能手机相仿。在接口方面,Raspberry Pi提供了可供键鼠使用的USB接口,此外 227 | 还有千兆以太网接口、SD卡扩展接口以及1个HDMI高清视频输出接口,可与显示器或者TV相连。 228 | 229 | Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的 230 | 多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软 231 | 件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为 232 | 核心的设计思想,是一个性能稳定的多用户网络操作系统。 233 | 234 | Raspberry Pi相比于一般的ARM开发板来说,由于其本身搭载着Linux操作系统,可以用 235 | 诸如Python、Ruby或Bash来执行脚本,而不是通过编译程序来运行,具有更高的开发效率。 236 | 237 | 238 | ##辅助语言选择## 239 | 240 | **Python** 241 | 242 | Python, 是一种面向对象、直译式计算机程序设计语言,由Guido van Rossum于 243 | 1989年底发明,第一个公开发行版发行于1991年。Python语法简洁而清晰,具有 244 | 丰富和强大的类库。它常被昵称为胶水语言,它能够很轻松的把用其他语言制作 245 | 的各种模块(尤其是C/C++)轻松地联结在一起。常见的一种应用情形是,使用 246 | python快速生成程序的原型(有时甚至是程序的最终界面),然后对其中有特别 247 | 要求的部分,用更合适的语言改写,比如3D游戏中的图形渲染模块,速度要求非 248 | 常高,就可以用C++重写。 249 | 250 | **Ruby** 251 | 252 | Ruby,一种为简单快捷的面向对象编程(面向对象程序设计)而创的脚本语言, 253 | 在20世纪90年代由日本人松本行弘开发,遵守GPL协议和Ruby License。 254 | 255 | Python相对于Ruby有着更好的跨平台能力,同时有理好的可读性,加之Ruby语言 256 | 没有对串口通讯及Windows系统更好的支持。 257 | 258 | ##串口通信模块## 259 | 260 | **PySerial** 261 | 262 | PySerial封装了串口通讯模块,支持Linux、Windows、BSD(可能支持所有支持POSIX的操 263 | 作系统),支持Jython(Java)和IconPython(.NET and Mono). 264 | 265 | 在使用PySerial之后,我们只需要 266 | 267 | ``` python 268 | ser=serial.Serial("/dev/ttyACM0",9600) 269 | ser.write("1") 270 | ``` 271 | 就可以向串口发送一个字符1。 272 | 273 | ##网页通信## 274 | 275 | **Ajax** 276 | AJAX [^ajax] 是由Jesse James Gaiiett创造的名词,是指一种创建交互式网页 277 | 应用的网页开发技术。 278 | 279 | 系统主要用Ajax来实现实时温度显示,通过直接访问JSON数据的情况下,可以在 280 | 不需要刷新页面的情况下直接读取数据。 281 | 282 | 283 | [^ajax]: Asynchronous JavaScript and XML(异步JavaScript和XML) 284 | 285 | ##数据可视化框架选择## 286 | 287 | **HighCharts** 288 | 289 | Highcharts 是一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在 290 | web网站或是web应用程序添加有交互性的图表,并且免费提供给个人学习、个人 291 | 网站和非商业用途使用。HighCharts支持的图表类型有曲线图、区域图、柱状图、 292 | 饼状图、散状点图和综合图表。 293 | 294 | 295 | #本地系统设计 296 | 297 | ##硬件设计 298 | 299 | ###Raspberry Pi 300 | 301 | Raspberry Pi开发板在这里主要工作有: 302 | 303 | - 与Arduino开发板,通过USB线连接。 304 | - 可以直接运行Debian GNU/Linux系统,通过网线上网,并从服务器中读取数据, 305 | - 通过Python语言接收、发送串口数据。 306 | 307 | ##软件设计## 308 | 在本地我们需要解决的问题可以如下描述,Arduino开发板从串口一直读取数据, 309 | Raspberry Pi从URL中验证数据、解析数据,再将数据发送到串口,我们可以用下面的伪代码来描述: 310 | 311 | ``` ada 312 | arduino: 313 | begin 314 | repeat 315 | wait(serial.open) 316 | data:=receive_data() 317 | led_status:=parse(data) 318 | if led_status 319 | oped(led.id) 320 | util false 321 | end 322 | raspberrypi: 323 | begin 324 | repeat 325 | json:=get_data(url) 326 | if validate(json).success() 327 | data:=parse(json) 328 | serial.write(data) 329 | util false 330 | end 331 | ``` 332 | 333 | ##Arduino## 334 | 335 | [arduinouno]: https://raw.githubusercontent.com/phodal/thesis/master/dot/ArduinoUnoSmd.png "Arduino开发板" 336 | ![Arduino开发板][arduinouno] 337 | 338 | 339 | Arduino UNO用的处微控制器是Atmega328,它与Arduino芯片的对应关系如下所示 340 | 341 | [atmega328]: https://raw.githubusercontent.com/phodal/thesis/master/dot/atmega328w.png "Arduino管脚Atmega328对应图" 342 | ![Arduino管脚Atmega328对应图][atmega328] 343 | 344 | 其主要参数如下所示: 345 | 346 | 高性能,低功耗的AVR®8位微控制器•先进的RISC结构 347 | 348 | - 131条指令 349 | - 绝大多数为单时钟周期执行 350 | - 32个通用工作寄存器 351 | - 全静态工作 352 | - 高达20 MIPS的吞吐量,在20 MHz 353 | - 片上2周期乘法器高耐用性非易失性内存段 354 | - 8K字节的系统内可编程Flash存储器(ATMEGA88PA中) 355 | - 512字节的EEPROM(ATMEGA88PA) 356 | - 1K字节的片内SRAM(ATMEGA88PA) 357 | - 写/擦除次数:10,000次,000 EEPROM 358 | - 数据保存:20年在85°C/100年在25°C(1) 359 | - 可选的引导具有独立锁定位代码段在系统编程的片上引导程序真正的同时读 360 | - 写操作 361 | - 编程软件安全锁外设特点 362 | - 两个8位定时器/计数器具有独立预分频器和比较模式 363 | - 1个16位定时器/计数器具有独立预分频器,比较模式,并捕获模式 364 | - 具有独立振荡器的实时计数器 365 | - 6个PWM通道 366 | - 8通道10位ADC在TQFP和QFN / MLF封装温度测量 367 | - 6通道10位ADC引脚PDIP封装温度测量 368 | - 可编程的串行USART 369 | - 主/从机模式的SPI串行接口 370 | - 面向字节的两线串行接口(飞利浦公司的I2C兼容) 371 | - 独立的片内振荡器的可编程看门狗定时器 372 | - 片上模拟比较器 373 | - 中断和唤醒引脚电平变化单片机的特殊功能 374 | - 上电复位以及可编程的掉电检测 375 | - 内部校准振荡器 376 | - 外部和内部中断源 377 | - 6种睡眠模式:空闲模式,ADC噪声抑制,省电,掉电,待机,扩展Standby 378 | 379 | Arduino部分硬件程序如下所示,主要负责从串口中读入数据,并用led灯显示。 380 | 程序流程图如下所示 381 | 382 | [image]: https://raw.githubusercontent.com/phodal/thesis/master/dot/arduino.png "Arduino程序流程图" 383 | ![Arduino程序流程图][image] 384 | 385 | 系统主要的功能在于接收和传递数据。 386 | 387 | 代码如下所示 388 | 389 | 390 | void setup() { 391 | Serial.begin(9600); 392 | pinMode(13,OUTPUT); 393 | pinMode(12,OUTPUT); 394 | } 395 | 396 | int serialData; 397 | void loop() { 398 | String inString = ""; 399 | while (Serial.available()> 0) 400 | { 401 | int inChar = Serial.read(); 402 | if (isDigit(inChar)) { 403 | inString += (char)inChar; 404 | } 405 | serialData=inString.toInt(); 406 | Serial.print(serialData); 407 | } 408 | if(serialData==1){ 409 | digitalWrite(12,LOW); 410 | digitalWrite(13,HIGH); 411 | }else{ 412 | digitalWrite(13,LOW); 413 | digitalWrite(12,HIGH); 414 | } 415 | 416 | 417 | 418 | ##Raspberry Pi## 419 | Raspberrypi如下所示的开发板 420 | 421 | [raspi]: https://raw.githubusercontent.com/phodal/thesis/master/dot/raspberrypi.png "Raspberry Pi开发板" 422 | ![Raspberry Pi开发板][raspi] 423 | 424 | ``` 425 | begin 426 | repeat 427 | json:=get_data(url) 428 | if validate(json).success 429 | data:=parse(json) 430 | if data:==1 431 | serial_send("1") 432 | else 433 | serial_send("0") 434 | else 435 | output "error" 436 | util false 437 | end 438 | ``` 439 | 440 | ####Raspberry Pi程序#### 441 | 442 | 其程序流程图如下所示: 443 | 444 | [python2]: https://raw.githubusercontent.com/phodal/thesis/master/dot/python.png "Python 程序流程图" 445 | ![Python程序流程图][python2] 446 | 447 | ###获取数据### 448 | 449 | Raspberry Pi端的主要功能便是将数据从 450 | [http://www.xianuniversity.com/athome/1][xianuniversity] [^domain] 下 451 | 载下来并解析数据,再将数据用串口通讯的方式传递给Arduino。 452 | 453 | 在Debian系统中,自带了python语言,python有良好的动态特性,同时有强大的自建库功能。 454 | 在python语言中可以用自带的urllib2库打开并下载网页的内容,将上述网址中 455 | 的JSON数据下载到本地。 456 | 457 | 数据采用的是JSON格式,具有良好的可读性,同时方便于解析,相比于XML格式 458 | 又可以减少文件大小, 459 | 460 | ``` javascript 461 | [{ 462 | "id": 1, 463 | "temperature": 10, 464 | "sensors1": 22, 465 | "sensors2": 11, 466 | "led1": 0 467 | }] 468 | ``` 469 | 470 | [xianuniversity]:http://www.xianuniversity.com/athome/1 471 | 472 | JSON的 473 | 将上述中的数据取出来后,通过python中的json库,将json数据转换为数组,将 474 | 取出数据中的第一个结果中的id的值。 475 | 476 | ###串口通讯### 477 | 由于python中没有用于串口通讯的库,需要寻找并安装这样一个库,这里就用到 478 | 了pip这样的包管理工具——用于管理python的库。 479 | 480 | ####安装pyserial#### 481 | 482 | pip常用命令有install、uninstall以及search,install顾名思义就是安装,安 483 | 装pip库如下所示[^windows],如后代码如下所示,$[^dollar]开头: 484 | 485 | 486 | ``` bash 487 | $pip install pyserial 488 | ``` 489 | 490 | [^dollar]:指在*nix系统的终端中执行的命令。 491 | [^windows]:在Windows系统中需要先安装pip,再安装pyserial。 492 | 493 | ###python串口通讯### 494 | 在Linux内核的系统[^windows_com]中虚拟串口用的节点是ttyACM,位于/dev目录下。 495 | 496 | ``` python 497 | serial.Serial("/dev/ttyACM0",9600) 498 | ``` 499 | 500 | 串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去, 501 | 同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能 502 | 的电路,我们称为串行接口电路。 503 | 504 | 便是打开这个设备,以9600的速率传输数据。 505 | 506 | import json 507 | import urllib2 508 | import serial 509 | import time 510 | 511 | url="http://www.xianuniversity.com/athome/1" 512 | 513 | while 1: 514 | try: 515 | date=urllib2.urlopen(url) 516 | result=json.load(date) 517 | status=result[0]["led1"] 518 | ser=serial.Serial("/dev/ttyACM0",9600) 519 | if status==1 : 520 | ser.write("1") 521 | elif status==0: 522 | ser.write("0") 523 | time.sleep(1) 524 | except urllib2.URLError: 525 | print "Bad URL or timeout" 526 | 527 | [^windows_com]:在Windows系统上,只需要将/dev/ttyACM0改为对应的com口。 528 | [getjson]: https://raw.githubusercontent.com/phodal/thesis/master/dot/getjson.png "python返回json数据" 529 | ![python返回json数据][getjson] 530 | 531 | 系统还需要对上面的数据进行处理,只拿其中的结果 532 | 533 | [originjson]: https://raw.githubusercontent.com/phodal/thesis/master/dot/origin.png "python处理完后的结果" 534 | ![python处理完后的结果][originjson] 535 | 536 | 当改变led的状态后,便可以得到下面的结果 537 | 538 | [changejson]: https://raw.githubusercontent.com/phodal/thesis/master/dot/change.png "改变状态后的结果" 539 | ![改变状态后的结果][changejson] 540 | 541 | #网络系统设计# 542 | 543 | ##网络服务程序设计## 544 | 545 | 对于物联网系统网络的核心是构建一个RESTful服务,而这构建RESTful的核心便 546 | 是基础的HTPP协议。基础的HTTP协议便是:GET、POST、PUT、DELETE。它们分别 547 | 对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资 548 | 源),PUT用来更新资源,DELETE用来删除资源。 549 | 550 | [restful]: https://raw.githubusercontent.com/phodal/thesis/master/dot/restful.png "restful" 551 | ![restful][restful] 552 | 553 | 简要的来说,一个GET动作便是在打开一个网页的时候,看到的内容,便是GET到 554 | 的资源。而在获取取到网页的内容之前,会有一个POST动作到所要打开的网站的 555 | 服务器。 556 | 557 | [getrequest]: https://raw.githubusercontent.com/phodal/thesis/master/dot/getrequest.png "Get Request" 558 | ![Get Request][getrequest] 559 | 560 | ###基本的REST服务### 561 | 562 | REST服务实际上是充当着网络与设备的传输介质,构建一个REST服务也就相当于 563 | 获取一个URL下的某个数据 564 | 565 | $curl http://www.xianuniversity.com/athome/1 566 | 567 | 返回结果如下所示 568 | 569 | [jsondata]: https://raw.githubusercontent.com/phodal/thesis/master/dot/jsondata.png "JSON结果返回图" 570 | ![JSON结果返回图][jsondata] 571 | 572 | 假设有这样一个资源用于呈现led的状态,即 http://localhost/status/1 573 | [^localhost],获取这个LED的状态便发出了类似下面这样的请求: 574 | 575 | ``` python 576 | GET /status/1 HTTP/1.1 577 | Host:localhost 578 | Cotent-Type:application/json;charset=UTF-8 579 | ``` 580 | [^localhost]:在本地进行web开发时,浏览器可以识别localhost,配置好Hosts时相当于127.0.0.1。 581 | 582 | 在客户端发出上述的请求的时候,服务端需要对其做出响应,构造出一个下面的结果 583 | ``` javascript 584 | [{ 585 | "status":1 586 | }] 587 | ``` 588 | 1代表给予灯的状态应该是亮的,在那之后需要做的便是将其通过串口发送给单片 589 | 机进行处理,对应于一个关机的结果便是 590 | 591 | ``` javascript 592 | [{ 593 | "status":0 594 | }] 595 | ``` 596 | 这样就完成了基本的状态设计。而对于系统最后需要解析的数据的结果来说,还需要加入其他元素, 597 | ``` javascript 598 | [{ 599 | "id": 1, 600 | "temperature": 10, 601 | "sensors1": 22, 602 | "sensors2": 11, 603 | "led1": 0 604 | }] 605 | ``` 606 | 这里也涉及到了json数据结构的设计,可以将上面的结果设计为 607 | ``` javascript 608 | [{ 609 | "id": 1, 610 | "temperature": 10, 611 | "sensors":[{ 612 | "sensor":22, 613 | "sensor":11, 614 | }], 615 | "led1": 0 616 | }] 617 | ``` 618 | 这种具有更好的可读性,然而在对于网速速度要求高的情况下,会表现得不好, 619 | 同时会造成额外的系统开销。对于这样一个需要不断读取数据的系统来说,采用 620 | 单层结构的json数据会更具有优势。 621 | 622 | 在设计这样一个接口的时候,需要考虑客户端可能需要获取全部的数据 623 | ``` python 624 | GET /status HTTP/1.1 625 | Host:localhost 626 | Cotent-Type:application/json;charset=UTF-8 627 | ``` 628 | 设计好这样的接口有助于显示在系统的前台,而这也是无法在物联网系统中产生 629 | 统一协议的原因之一,复杂的接口无法用于简单功能的场景。 630 | 631 | 下面是一个简单的POST请求的示例,系统需要能接收POST请求,并将请求存储到数据库 632 | 633 | ``` bash 634 | POST / HTTP/1.1 635 | Host:localhost 636 | User-Agent: Go 1.1 package http 637 | Content-Length: 45 638 | Authorization: 123456 639 | Accept-Encoding: gzip 640 | ``` 641 | 一个PUT动作但是我们更新资源,就好比是我们创建一个日志或者一个说说一样。 642 | DELETE动作,便是删除动作了,而这也是一个物联网系统服务所需要的。 643 | 644 | ##系统前台设计## 645 | 在对系统前台设计的时候,在考虑不同移动设备的兼容的同时,也需要保持一个 646 | 良好可用的结构。而系统在前台的主要功能是在于控制物体的状态、显示一些数 647 | 值的变化,控制物体状态的关键在于如何将数据由前台POST到后台,在网页端可 648 | 以用POST,而在移动端则可以用JSON API。 649 | 650 | ###Ajax### 651 | 652 | - AJAX : Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。 653 | - AJAX 不是新的编程语言,而是一种使用现有标准的新方法。 654 | - AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。 655 | 656 | 剥离后的Ajax部分代码如下所示,主要用的是 jQuery 框架的 getJSON 来实现的 657 | 658 | begin 659 | data:=get_data(url) 660 | if data.get_success 661 | temperature:=data.push(temperature) 662 | 663 | [editjson]: https://raw.githubusercontent.com/phodal/thesis/master/dot/edit.png "控制界面" 664 | ![控制界面][editjson] 665 | 666 | 当按下Change Status按钮时,系统发生了如下变化 667 | 668 | [getpost]: https://raw.githubusercontent.com/phodal/thesis/master/dot/getpost.png "GET POST数据" 669 | ![GET POST数据][getpost] 670 | 671 | 系统会先向服务器发送数据,也就是POST请求,在请求结束后,系统将会刷新页面,也就是GET请求。 672 | 673 | 系统会不断从后台获取数据结果,如下所示 674 | 675 | [request]: https://raw.githubusercontent.com/phodal/thesis/master/dot/request.png "后台获取数据" 676 | ![后台获取数据][request] 677 | 678 | 在Javascript语言中有函数库可以直接用于获取后台数据——getJSON,可以从指定的URL中获取结果。 679 | 680 | - url 用于提供 json 数据的地址页 681 | - data(Optional) 用于传送到服务器的键值对 682 | - callback(Optional) 回调函数,json 数据请求成功后的处理函数 683 | 684 | 685 | ``` javascript 686 | var dataLength = []; 687 | function drawTemp() { 688 | var zero = []; 689 | $.getJSON('/athome/', function(json) { 690 | var items = []; 691 | dataLength.push(json.length); 692 | $.each(json, function(key, val) { 693 | zero.push(val.temperature); 694 | }); 695 | }; 696 | ``` 697 | 698 | 实际上,上面的程序只是从 /athome/ 下面获取数据,再将数据堆到数组里面,再 699 | 把这部分放到图形中。 700 | 701 | ###Highcharts### 702 | 703 | Highcharts有以下的特点 704 | 705 | - 兼容性:兼容当今所有的浏览器,包括 iPhone、IE 和火狐等等; 706 | - 对个人用户完全免费; 707 | - 纯JS,无BS; 708 | - 支持大部分的图表类型:直线图,曲线图、区域图、区域曲线图、柱状图、饼装图、散布图; 709 | - 跨语言:不管是 PHP、Asp.net 还是 Java 都可以使用,它只需要三个文件:一个是Highcharts 710 | 的核心文件 highcharts.js,还有 a canvas emulator for IE 和 Jquery类库或者 MooTools 类库; 711 | - 提示功能:鼠标移动到图表的某一点上有提示信息; 712 | - 放大功能:选中图表部分放大,近距离观察图表; 713 | - 易用性:无需要特殊的开发技能,只需要设置一下选项就可以制作适合自己的图表; 714 | - 时间轴:可以精确到毫秒; 715 | 716 | 在这里只需将需要处理的数据存储到数组中,便可以将其渲染成为图形,下面的温度走势图便是基于Highcharts的结果 717 | 718 | [chart1]: https://raw.githubusercontent.com/phodal/thesis/master/dot/chart.png "温度走势图" 719 | ![chart][chart1] 720 | 721 | ##系统后台设计## 722 | 723 | ###数据库设计### 724 | 725 | 系统使用Laravel框架作为系统底层,需要配置其运行环境[^runtime],创建数 726 | 据库[^createdb],对应于上面生成的最后的JSON数据,创建对应的数据库: 727 | 728 | 系统数据库结构如下所示 729 | 730 | | 表名 | 数据类型 | 作用 | 731 | | ---- |-------- | ------ | 732 | | id | 整数 | ID | 733 | | temperature | 浮点数 | 温度 | 734 | | sensors1 | 浮点数 | 传感器1 | 735 | | sensors2 | 浮点数 | 传感器2 | 736 | | led1 | 布尔型 | led状态 | 737 | 738 | 对应于数据库,其相应的php代码如下所示 739 | 740 | ``` php 741 | public function up() 742 | { 743 | Schema::create('athomes', function(Blueprint $table) 744 | { 745 | $table--->increments('id'); 746 | $table->float('temperature'); 747 | $table->float('sensors1'); 748 | $table->float('sensors2'); 749 | $table->boolean('led1'); 750 | $table->timestamps(); 751 | }); 752 | } 753 | ``` 754 | 755 | 当POST数据的时候,便是将数据存往数据库,而GET的时候则是从数据库中拿出 756 | 数据再渲染给浏览器,GET、PUT、DELETE、POST便是对就于数据库的Create、Refresh、Update、Delete 757 | 758 | 系统使用MySQL作为数据库,开始的时候需要创建数据库,在数据库中执行 759 | 760 | CREATE DATABASE IF NOT EXISTS iot default charset utf8 COLLATE utf8_general_ci; 761 | 762 | 用于创建一个athomes数据库,同时将PHP与数据库配置好 763 | 764 | ```php 765 | 'mysql' => array( 766 | 'driver' => 'mysql', 767 | 'host' => 'localhost', 768 | 'database' => 'iot', 769 | 'username' => 'root', 770 | 'password' => ' ', 771 | 'charset' => 'utf8', 772 | 'collation' => 'utf8_unicode_ci', 773 | 'prefix' => '', 774 | ) 775 | ``` 776 | 777 | 当用户在前台创建一个数据后,可以在MySQL的后台查看: 778 | 779 | 780 | id | temperature | sensors1 | sensors2 | led1 | created_at | updated_at 781 | ----|-------------|----------|----------|------|---------------------|--------------------- 782 | 1 | 19.80 | 22.20 | 7.50 | 0 | 2013-12-31 07:03:59 | 2013-12-31 07:03:59 783 | 2 | 18.80 | 22.00 | 7.60 | 0 | 2013-12-31 07:03:59 | 2013-12-31 07:03:59 784 | 785 | 786 | [^runtime]:这里用的是Linux+Nginx+MySQL+PHP。 787 | [^createdb]:创建数据的代码:CREATE DATABASE IF NOT EXISTS bbs default charset utf8 COLLATE utf8_general_ci; 788 | --------------------------------------------------------------------------------