├── .gitignore ├── .nojekyll ├── Licence.txt ├── Makefile ├── README.md ├── build ├── 1.1.anywhere-html.md.html ├── 1.2.anywhere-javascript.md.html ├── 1.3.anywhere-css.md.html ├── 1.4.anywhere-hjc.md.html ├── 1.5.linux.md.html ├── 1.6.arduino.md.html ├── 1.7.python.md.html ├── 1.8.rpi.md.html ├── 1.9.server.md.html ├── 1.pre.md.html ├── 2.0.webservices.md.html ├── 2.1.http.md.html ├── 2.1.restful.md.html ├── 2.2.init_env.md.html ├── 2.3.create_laravel.md.html ├── 2.5.frontend.md.html ├── 2.intro.md.html ├── 3.1.coap.md.html ├── 3.1.iot-coap.md.html ├── 3.2.mqtt.md.html ├── 4.0.easyiot.md.html ├── 5.0.android.md.html ├── designiot.epub ├── designiot.mobi └── qa.md.html ├── css └── vendor.css ├── designiot.jpg ├── end └── iot.md ├── help.md ├── images ├── 88x31.png ├── arch.jpeg ├── arduino.png ├── box-model.gif ├── change.png ├── dom_tree.jpg ├── edit.png ├── flow.png ├── fullconnected.png ├── getjson.png ├── gnu_linux.png ├── gpio.png ├── hardware.jpg ├── hwcnt.png ├── linux_kernel.jpg ├── lnmp.gif ├── lnmp.jpg ├── nostyle.png ├── origin.png ├── pm.png ├── python.png ├── raspberrypi_flow.png ├── redfonts.png ├── rpi.jpg ├── shell.png ├── star.png ├── temperture.png ├── uno.png ├── webkitflow.png └── xml-vs-json.png ├── index.html ├── iot.html ├── src ├── 1.1.anywhere-html.md ├── 1.2.anywhere-javascript.md ├── 1.3.anywhere-css.md ├── 1.4.anywhere-hjc.md ├── 1.5.linux.md ├── 1.6.arduino.md ├── 1.7.python.md ├── 1.8.rpi.md ├── 1.9.server.md ├── 2.0.webservices.md ├── 2.1.http.md ├── 2.1.restful.md ├── 2.2.init_env.md ├── 2.3.create_laravel.md ├── 2.5.frontend.md ├── 3.1.coap.md ├── 3.1.iot-coap.md ├── 4.0.easyiot.md ├── 5.0.android.md ├── end │ └── qa.md ├── futrue │ └── 3.2.mqtt.md └── pre │ ├── 1.pre.md │ └── 2.intro.md └── template ├── head-chapter.html ├── head.html ├── headpdf.html ├── pdf.html └── template.tex /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | build/iot.pdf 3 | build/designiot.pdf 4 | Makefile.old 5 | build/pdf.html -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /build/1.1.anywhere-html.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 74 |
75 |

某一天,正走在回学校的路上的我突然想到:“未来将会是一个科技的时代——虽然现在也是——只是在未来,科技将会无处不在。如果我们依旧对周围这些无处不在的代码一无所知的话,或许我们会成为黑客帝国之中被控制的普通人。”于是开始想着,有一天人们会像学习一门语言一样开始学习编程,直到又有一天我看到了学习编程如同学习一门语言的说法。这又恰好在我做完最小物联网系统之后,算是一个有趣的时间点,我开始想着像之前做最小物联网系统的那些步骤一样,写一个简单的入门。也可以补充好之前在这个最小物联网系统缺失的那些东西,给那些正在开始试图去解决编程问题的人。

76 |

让我们先从身边的语言下手,也就是现在无处不在的html+javascript+css。

77 |

1 无处不在的HTML

78 |

之所以从html开始,是因为我们不需要配置一个复杂的开发环境,也许你还不知道开发环境是什么东西,不过这也没关系,毕竟这些知识需要慢慢的接触才能有所了解,尤其是对于普通的业余爱好者来说,当然,对于专业选手言自然不是问题。HTML是Web的核心语言,也算是比较基础的语言。

79 |

1.1 html的hello,world

80 |

Hello,world是一个传统,所以在这里也遵循这个有趣的传统,我们所要做的事情其实很简单,虽然也有一点点hack的感觉。——让我们先来新建一个文并命名为“helloworld.html”。

81 |

(PS:大部分人应该都是在windows环境下工作的,所以你需要新建一个文本,然后重命名,或者你需要一个编辑器,在这里我们推荐用sublime text。破解不破解,注册不注册都不会对你的使用有太多的影响。)

82 |
    83 |
  1. 新建文件

  2. 84 |
  3. 输入 85 |
    hello,world
  4. 86 |
  5. 保存为->“helloworld.html”,

  6. 87 |
  7. 双击打开这个文件。 正常情况下都应该是用你的默认浏览器打开。只要是一个正常工作的现代浏览器,都应该可以看到上面显示的是“Hello,world”。

  8. 88 |
89 |

这才是最短的hello,world程序,但是呢?在ruby中会是这样子的

90 |
2.0.0-p353 :001 > p "hello,world"
 91 | "hello,world"
 92 |     => "hello,world"
 93 | 2.0.0-p353 :002 >
94 |

等等,如果你了解过html的话,会觉得这一点都不符合语法规则,但是他工作了,没有什么比安装完Nginx后看到It works!更让人激动了。

95 |

遗憾的是,它可能无法在所有的浏览器上工作,所以我们需要去调试其中的bug。

96 |

1.1.1 调试hello,world

97 |

我们会发现我们的代码在浏览器中变成了下面的代码,如果你和我一样用的是chrome,那么你可以右键浏览器中的空白区域,点击审查元素,就会看到下面的代码。

98 |
<html>
 99 |     <head></head>
100 |     <body>hello,world</body>
101 | </html>
102 |

这个才是真正能在大部分浏览器上工作的代码,所以复制它到编辑器里吧。

103 |

1.1.2 说说hello,world

104 | 我很不喜欢其中的<*></*>,但是我也没有找到别的方法来代替它们,所以这是一个设计得当的语言。甚至大部分人都说这算不上是一门真正的语言,不过html的原义是 105 |
106 | 超文本标记语言 107 |
108 |

所以我们可以发现其中的关键词是标记——markup,也就是说html是一个markup,head是一个markup,body也是一个markup。

109 |

然而,我们真正工作的代码是在body里面,至于为什么是在这里面,这个问题就太复杂了。打个比方来说:

110 |
    111 |
  1. 我们所使用的汉语是人类用智慧创造的,我们所正在学的这门语言同样也是人类创造的。

  2. 112 |
  3. 我们在自己的语言里遵循着桌子是桌子,凳子是凳子的原则,很少有人会问为什么。

  4. 113 |
114 |

1.1.3 想用中文?

115 |

所以我们也可以把计算机语言与现实世界里用于交流沟通的语言划上一个等号。而我们所要学习的语言,并不是我们最熟悉的汉语语言,所以我们便觉得这些很复杂,但是如果我们试着用汉语替换掉上面的代码的话

116 |
<语言>
117 |     <头><结束头>
118 |     <身体>你好,世界<结束身体>
119 | <结束语言>
120 |

这看上去很奇怪,只是因为是直译过去的原因,也许你会觉得这样会好理解一点,但是输入上可就一点儿也不方便,因为这键盘本身就不适合我们去输入汉字,同时也意味着可能你输入的会有问题。

121 |

让我们把上面的代码代替掉原来的代码然后保存,打开浏览器会看到下面的结果

122 |
<语言> <头><结束头> <身体>你好,世界<结束身体> <结束语言>
123 |

更不幸的结果可能是

124 |
<璇█> <澶�><缁撴潫澶�> <韬綋>浣犲ソ锛屼笘鐣�<缁撴潫韬綋> <缁撴潫璇█>
125 |

这是一个编码问题,对中文支持不友好。

126 |

我们把上面的代码改为和标记语言一样的结构

127 |
<语言>
128 |     <头></头>
129 |     <身体>你好,世界</身体>
130 | <结束语言>
131 |

于是我们看到的结果便是

132 |
<语言> <头> <身体>你好,世界
133 |

被chrome浏览器解析成什么样了?

134 |
<html><head></head><body><语言>
135 |         <头><!--头-->
136 |         <身体>你好,世界<!--身体-->
137 |     <!--语言-->
138 | </body></html>      
139 |

140 |

结尾的是注释,写给人看的代码,不是给机器看的,所以机器不会去理解这些代码。

141 |

但是当我们把代码改成

142 |
<whatwewanttosay>你好世界</whatwewanttosay>
143 |

浏览器上面显示的内容就变成了

144 |
你好世界
145 |

或许你会觉得很神奇,但是这一点儿也不神奇,虽然我们的中文语法也遵循着标记语言的标准,但是我们的浏览器不支持中文标记。

146 |

结论:

147 |
    148 |
  1. 浏览器对中文支持不友好。
  2. 149 |
  3. 浏览器对英文支持友好。
  4. 150 |
151 |

刚开始的时候不要对中文编程有太多的想法,这是很不现实的:

152 |
    153 |
  1. 现有的系统都是基于英语语言环境构建的,对中文支持不是很友好。
  2. 154 |
  3. 中文输入的速度在某种程度上来说没有英语快。
  4. 155 |
156 |

我们离开话题已经很远了,但是这里说的都是针对于那些不满于英语的人来说的,只有当我们可以从头构建一个中文系统的时候才是可行的,而这些就要将cpu、软件、硬件都包含在内,甚至我们还需要考虑重新设计cpu的结构,在某种程度上来说会有些不现实。或许,需要一代又一代人的努力。忘记那些吧,师夷长之技以治夷。

157 |

1.2 其他html标记

158 |

添加一个标题,

159 |
<html>
160 |     <head>
161 |         <title>标题</title>
162 |     </head>
163 |     <body>hello,world</body>
164 | </html>
165 |

我们便可以在浏览器的最上方看到“标题”二字,就像我们常用的淘宝网,也包含了上面的东西,只是还包括了更多的东西,所以你也可以看懂那些我们可以看到的淘宝的标题。

166 |
<html>
167 | <head>
168 |     <title>标题</title>
169 | </head>
170 | <body>
171 | hello,world
172 | <h1>大标题</h1>
173 | <h2>次标题</h2>
174 | <h3>...</h3>
175 | <ul>
176 |     <li>列表1</li>
177 |     <li>列表2</li>
178 | </ul>
179 | </body>
180 | </html>
181 |

更多的东西可以在一些书籍上看到,这边所要说的只是一次简单的语言入门,其他的东西都和这些类似。

182 |

1.2.1 美妙之处

183 |

我们简单地上手了一门不算是语言的语言,浏览器简化了这其中的大部分过程,虽然没有C和其他语言来得有专业感,但是我们试着去开始写代码了。我们可能在未来的某一篇中可能会看到类似的语言,诸如python,我们所要做的就是

184 |
$ python file.py
185 | =>hello,world
186 |

然后在终端上返回结果。只是因为在我看来学会html是有意义的,简单的上手,然后再慢慢地深入,如果一开始我们就去理解指针,开始去理解类。我们甚至还知道程序是怎么编译运行的时候,在这个过程中又发生了什么。虽然现在我们也没能理解这其中发生了什么,但是至少展示了

187 |
    188 |
  1. 中文编程语言在当前意义不大,不现实,效率不高兼容性差
  2. 189 |
  3. 语言的语法是固定的。(ps:虽然我们也可以进行扩充,我们将会在后来支持上述的中文标记。)
  4. 190 |
  5. 已经开始写代码,而不是还在配置开发环境。
  6. 191 |
  7. 随身的工具才是最好的,最常用的code也才是实在的。
  8. 192 |
193 |

1.2.2 更多

194 |

我们还没有试着去解决“某商店里的糖一颗5块钱,小明买了3颗糖,小明一共花了多少钱”的问题。也就是说我们学会的是一个还不能解决实际问题的语言,于是我们还需要学点东西,比如javascript,css。我们可以将Javascript理解为解决问题的语言,html则是前端显示,css是配置文件,这样的话,我们会在那之后学会成为一个近乎专业的程序员。我们刚刚学习了一下怎么在前端显示那些代码的行为,于是我们还需要Javascript。

195 | 196 | 197 | -------------------------------------------------------------------------------- /build/1.6.arduino.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 72 |
73 |

1 Arduino 极客的玩具

74 |

1.1 极客的玩具

75 |

Arduino,是一个开放源代码的单芯片微电脑,它使用了Atmel AVR单片机,采用了基于开放源代码的软硬件平台,构建于开放源代码 simple I/O 接口板,并且具有使用类似Java,C 语言的Processing/Wiring开发环境。

76 |

Arduino开发板封装了常用的库到开发环境中,可以让用户在开发产品时,将主要注意力放置于所需要实现的功能上,而不是开发的过程中。在为Arduino写串口程序时,我们只需要用Serial.begin(9600)以9600的速率初始化串口,而在往串口发送数据时,可以用Serial.write(‘1’)的方式向串口发送字串’1’。

77 |

Arduino的出现很大程度上降低了电子制作的难度,初学者甚至不懂编程也可以上手Arduino,这也是它的魅力所在。

78 |

1.2 硬件熟悉

79 |

为了满足各种需求,Arduino团队设计了很多款开发板,如UNO、Pro mini、Mega2560、Due、Leonardo、Yún、Pro、Fio、Nano等十几种 开发板和扩展板。最适合初学者的一款是Arduino UNO 。下图是Arduino UNO 的外观图:

80 |
81 | UNO 82 |

UNO

83 |
84 |

注:后面的程序也是基于Arduino UNO开发板来讲解。

85 |

1.3 开发环境

86 |
87 | Arduino 88 |

Arduino

89 |
90 |

开发环境如上图,十分简洁,编写代码需要知道两个基本的函数:

91 |
void setup(){
 92 | 
 93 | }
 94 | 
 95 | void loop(){
 96 | 
 97 | }
98 |

setup()函数用于初始化(如GPIO初始化,串口初始化,定时器初始化等)特点是只执行一次;loop()函数是一个死循环,可以看做C语言的while(1)函数。

99 |

1.4 点亮一个LED

100 |

对初学者来说,点亮led已成为入门必修课,使用Arduino控制led十分简单,并且很容易理解。 使用到的函数:

101 | 105 |

上一段代码分析:

106 |
int led=13; 
107 | 
108 | void setup()
109 | {
110 |     pinMode(led,OUTPUT);
111 | }
112 | void loop()
113 | {
114 |     digitalWrite(led,HIGH);
115 |     delay(1000);
116 |     digitalWrite(led,LOW);
117 |     delay(1000);
118 | }
119 |

该程序实现Arduino单片机13号引脚以1S时间电平翻转,如果外接一个led,就可以看到led以1S的间隔闪烁;函数pinMode()有两个参数pin、value,pin参数用来指定引脚号,本程序中设置为13号引脚,mode用于设置引脚模式,有三个值:

120 | 125 |

表示让某一个IO引脚作输入,反之,

126 | 130 |

理解了pinMode()函数,digitalWrite()就很容易理解啦,value的取值有两个HIGHLOW,HIGH表示让某一个引脚输出高电平,反之,LOW则使某一个引脚输出低电平。 程序中还是用到delay(ms)函数,它表示延时多少毫秒,例如延时500 ms ,直接调用delay(500);就可以了。

131 |

如果你仔细查看我的描述,你会发现我没有讲13号引脚怎么来的,是这样的:Arduino团队为了简化对引脚描述,对每个引脚都进行了编号,以UNO开发板为例,可以发现开发板排座的附近有对应的白颜色的数字,那便是所有的引脚编号,A0~A5是6路ADC输入引脚,0-13表示13路基本IO,数字前面的~表示该引脚具有PWM功能。如果要使用某一引脚,只需要知道引脚编号就可编写相应代码进行操作。

132 |

例如digitalWrite(2,LOW)表示向2号引脚输出低电平。其他操作类似,是不是so easy - !

133 |

1.5 串口通信

134 |

使用到的基本函数:

135 | 141 |

在此项目中需要使用串口,Arduino串口初始化使用Serial.begin(9600);,其传输波特率为9600,其他波特率也行,函数位于setup()中,之后可以使用Serial.read()Serial.write()读入一个字符,输出一个字符,使用Serial.print()输出字符串.代码如下:

142 |
char ch='1';
143 | void setup()
144 | {
145 |     Serial.begin(9600);
146 | }
147 | void loop()
148 | {
149 |     Serial.write(ch);
150 |     while(1)
151 |     {
152 |         if(Serial.available())    
153 |         {
154 |             ch = Serial.read();
155 |             Serial.print(ch);
156 |         }
157 |     }
158 | }
159 |

以上程序实现字符的输出(Serial.write(),Serial.print())和读入(Serial.read())。如果需要了解更多,可以参考:Arduino官网

160 |

1.5.1 关于Arduino Setup()

161 |

如果你对Arduino的Setup很疑惑的话,可以看看这里。下面Arduino源码目录中的main函数:

162 |
#include <Arduino.h>
163 | 
164 | int main(void)
165 | {
166 |     init();
167 |     setup();        
168 |     for (;;) {
169 |         loop();
170 |         if (serialEventRun) serialEventRun();
171 |     }
172 |     return 0;
173 | }
174 |
175 | hwcnt 176 |

hwcnt

177 |
178 | 179 | 180 | -------------------------------------------------------------------------------- /build/1.8.rpi.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 68 |
69 |

1 Raspberry Pi

70 |
71 | Raspberry Pi 72 |

Raspberry Pi

73 |
74 |

1.1 Geek的盛宴

75 |

Raspberry Pi是一款针对电脑业余爱好者、教师、小学生以及小型企业等用户的迷你电脑,预装Linux系统,体积仅信用卡大小,搭载ARM架构处理器,运算性能和智能手机相仿。在接口方面,Raspberry Pi提供了可供键鼠使用的USB接口,此外还有千兆以太网接口、SD卡扩展接口以及1个HDMI高清视频输出接口,可与显示器或者TV相连。

76 |

Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

77 |

Raspberry Pi相比于一般的ARM开发板来说,由于其本身搭载着Linux操作系统,可以用诸如Python、Ruby或Bash来执行脚本,而不是通过编译程序来运行,具有更高的开发效率。

78 |

1.2 Raspberry Pi 初始化

79 |

今天的Raspbian默认已经安装openssh-server,并默认开启了OpenSSH-Server。

80 |

接着我们就可以看到系统启动了,要我们输入用户名和密码

81 |
Raspbian GNU/Linux 7 raspberrypi ttyAMA0
 82 | 
 83 | raspberrypi login: pi
 84 | Password:
 85 | Last login: Sat Apr 26 05:58:07 UTC 2014 on ttyAMA0
 86 | Linux raspberrypi 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l
 87 | 
 88 | The programs included with the Debian GNU/Linux system are free software;
 89 | the exact distribution terms for each program are described in the
 90 | individual files in /usr/share/doc/*/copyright.
 91 | 
 92 | Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
 93 | permitted by applicable law.
 94 | ls
 95 | 
 96 | NOTICE: the software on this Raspberry Pi has not been fully configured. Please run 'sudo raspi-config'
97 |

然后

98 |
sudo raspi-config
99 |

选择第一个,下面就可以继续了

100 |

Expand Filesystem Ensures that all of the SD card s

101 |

接着重启后,便可以扩展SD卡成功。

102 |

注: Raspbian与一般的Debian系统使用起来区别不是太大(ps:命令上),由于CPU是不同的架构,在编译上可能有所区别。通常PC上的软件需要重新编译才能在RPi上运行,所以如果可以用apt-get安装的话,就不要自己编译了。

103 |

1.3 Raspberry Pi GPIO

104 |
105 |

General Purpose Input Output (通用输入/输出)简称为GPIO,或总线扩展器,利用工业标准I2C、SMBus或SPI接口简化了I/O口的扩展。当微控制器或芯片组没有足够的I/O端口,或当系统需要采用远端串行通信或控制时,GPIO产品能够提供额外的控制和监视功能。

106 |
107 |
108 | GPIO 109 |

GPIO

110 |
111 | 112 | 113 | -------------------------------------------------------------------------------- /build/1.9.server.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 一步步搭建物联网系统(教你设计物联网系统) 15 | 16 | 17 | 18 | 19 | 20 |

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

21 | 22 | 23 |
24 | 31 |
32 |

1 Server 一切皆为服务

33 |

1.1 服务器

34 |

服务器(Server)指:

35 | 40 |

1.2 Web服务器

41 |

WEB服务器也称为WWW(WORLD WIDE WEB)服务器,主要功能是提供网上信息浏览服务。 WWW 是 Internet的多媒体信息查询工具,是 Internet 上近年才发展起来的服务,也是发展最快和目前用的最广泛的服务。正是因为有了WWW工具,才使得近年来 Internet 迅速发展,且用户数量飞速增长。

42 |

1.3 LNMP

43 |
44 | LNMP 45 |

LNMP

46 |
47 |

Linux+Nginx+MySQL+PHP

48 |
49 |

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发布。

50 |
51 |
52 |

MySQL 是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司。MySQL是最流行的关系型数据库管理系统,在WEB应用方面MySQL是最好的RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。

53 |
54 |
55 |

PHP于1994年由Rasmus Lerdorf创建,刚刚开始是Rasmus Lerdorf为了要维护个人网页而制作的一个简单的用Perl语言编写的程序。这些工具程序用来显示 Rasmus Lerdorf 的个人履历,以及统计网页流量。后来又用C语言重新编写,包括可以访问数据库。他将这些程序和一些表单直译器整合起来,称为 PHP/FI。PHP/FI 可以和数据库连接,产生简单的动态网页程序。

56 |
57 | 58 | 59 | -------------------------------------------------------------------------------- /build/1.pre.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 一步步搭建物联网系统(教你设计物联网系统) 15 | 16 | 17 | 18 | 19 | 20 |

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

21 | 22 | 23 |
24 | 30 |
31 |

本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。cc

32 |

© 2014 Phodal Huang.

33 |

1 前言

34 |

设计物联网系统是件有意思的事情,它需要考虑到软件、硬件、通讯等多个不同方面。通过探索不同的语言,不同的框架,从而形成不同的解决方案。

35 |

在这里,我们将对设计物联网系统有一个简单的介绍,并探讨如何设计一个最小的物联网系统。

36 |

1.1 目标读者

37 |

目标读者: 初入物联网领域,希望对物联网系统有一个大概的认识和把握,并学会掌握一个基础的物联网系统的设计。

38 | 52 |

本文档对一些概念(如)只做了一些基本介绍,以方便读者理解。如果您想进一步了解这些知识,会列出一些推荐书目,以供参考。

53 |

1.2 不适合人群

54 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /build/2.0.webservices.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 一步步搭建物联网系统(教你设计物联网系统) 15 | 16 | 17 | 18 | 19 | 20 |

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

21 | 22 | 23 |
24 | 29 |
30 |

1 Web服务

31 |

Web服务是一种服务导向架构的技术,通过标准的Web协议提供服务,目的是保证不同平台的应用服务可以互操作。

32 |

根据W3C的定义,Web服务(Web service)应当是一个软件系统,用以支持网络间不同机器的互动操作。网络服务通常是许多应用程序接口(API)所组成的,它们透过网络,例如国际互联网(Internet)的远程服务器端,执行客户所提交服务的请求。

33 |

尽管W3C的定义涵盖诸多相异且无法介分的系统,不过通常我们指有关于主从式架构(Client-server)之间根据SOAP协议进行传递XML格式消息。无论定义还是实现,WEB服务过程中会由服务器提供一个机器可读的描述(通常基于WSDL)以辨识服务器所提供的WEB服务。另外,虽然WSDL不是SOAP服务端点的必要条件,但目前基于Java的主流WEB服务开发框架往往需要WSDL实现客户端的源代码生成。一些工业标准化组织,比如WS-I,就在WEB服务定义中强制包含SOAP和WSDL。

34 |

WEB服务实际上是一组工具,并有多种不同的方法调用之。三种最普遍的手段是:

35 | 40 |

1.1 SOAP VS RESTful

41 |

简单对象访问协议是交换数据的一种协议规范,使用在计算机网络Web服务中,交换带结构信息。SOAP为了简化网页服务器从XML数据库中提取数据时,节省去格式化页面时间,以及不同应用程序之间按照HTTP通信协议,遵从XML格式执行资料互换,使其抽象于语言实现、平台和硬件。

42 | 43 | 44 | -------------------------------------------------------------------------------- /build/2.1.restful.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 一步步搭建物联网系统(教你设计物联网系统) 15 | 16 | 17 | 18 | 19 | 20 |

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

21 | 22 | 23 |
24 | 33 |
34 |

1 设计RESTful API

35 |
36 |

REST从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表征。获得这些表征致使这些应用程序转变了其状态。随着不断获取资源的表征,客户端应用不断地在转变着其状态,所谓表征状态转移。

37 |
38 |

因为我们需要的是一个Machine到Machine沟通的平台,需要设计一个API。而设计一个API来说,RESTful是很不错的一种选择,也是主流的选择。而设计一个RESTful服务,的首要步骤便是设计资源模型。

39 |

1.0.1 资源

40 |

互联网上的一切信息都可以看作是一种资源。

41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
HTTP MethodOperation Performed
GETGet a resource (Read a resource)
POSTCreate a resource
PUTUpdate a resource
DELETEDelete Resource
67 |

1.1 设计RESTful API

68 |

设计RESTful API是一个有意思的话题。下面是一些常用的RESTful设计原则:

69 |

1.2 REST关键目标

70 | 76 |

1.3 判断是否是 RESTful的约束条件

77 | 85 |

1.4 JSON

86 |
87 | xml-vs-json 88 |

xml-vs-json

89 |
90 | 91 | 92 | -------------------------------------------------------------------------------- /build/2.2.init_env.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 75 |
76 |

1 环境准备

77 |

1.1 Laravel

78 |
79 |

Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。

80 |
81 | 91 |

1.1.1 为什么是 Laravel

92 | 97 |

这里不会再重述之前的问题,这里只是将需要的步骤一个个写下来,然后丢到这里好好说一下。至于RESTful是什么,前面已经介绍了,就不再重复了。那么下面,我们就用Laravel来搭建一个平台给物联网用的。

98 |

1.2 安装 Laravel

99 |

1.2.1 GNU/Linux安装Composer

100 |

GNU/Linux Ubuntu/OpenSUSE下可以执行

101 |
$ curl -sS https://getcomposer.org/installer | php
102 |

1.2.1.1 Windows安装Composer

103 |

请直接下载

104 |

Composer-Setup

105 |

1.2.1.2 Mac OS

106 |

1.安装Composer

107 |
brew install homebrew/php/composer
108 |

2.安装Laravel

109 |
composer global require "laravel/installer=~1.1"
110 |

3.创建Laravel工程

111 |
composer create-project laravel/laravel your-project-name --prefer-dist 
112 |

1.2.1.3 Mac OS

113 |

1.下载laravel.phar

114 |
wget http://laravel.com/laravel.phar
115 |

2.重命名

116 |
mv laravel.phar laravel
117 |

3.移动到bin中

118 |
sudo mv laravel /usr/local/bin
119 |

4.创建项目

120 |
laravel new blog
121 |

1.3 MySQL

122 |

1.3.1 安装MySQL

123 |

出于某些原因,我建议用MariaDB替换MySQL,如果你"真正"需要mysql,将mariadb替换为mysql

124 |

ps: 在下文中我会继续用MySQL,而不是MariaDB,MairaDB是MySQL的一个分支,真正的开源分支。

125 |

Ubuntu/Debian/Mint

126 |
$ sudo apt-get install mariadb-server
127 |

Fedora/Centos

128 |
$ sudo yum install mariadb-server    
129 |

openSUSE

130 |
$ sudo zypper install mariadb-server
131 |

Mac OS

132 |
$ brew install mariadb
133 |

1.3.2 配置MySQL

134 |

修改database.php

135 |
app/config/database.php
136 |

要修改的就是这个

137 |
'mysql' => array(
138 |     'driver'    => 'mysql',
139 |     'host'      => 'localhost',
140 |     'database'  => 'iot',
141 |     'username'  => 'root',
142 |     'password'  => '940217',
143 |     'charset'   => 'utf8',
144 |     'collation' => 'utf8_unicode_ci',
145 |     'prefix'    => '',
146 | ),
147 |

如果你已经有phpmyadmin,似乎对你来说已经很简单了,如果没有的话,就直接用

148 |
$ mysql -uroot -p
149 |

来创建一个新的

150 |
CREATE DATABASE IF NOT EXISTS iot default charset utf8 COLLATE utf8_general_ci;
151 |

数据库的目的在于存储数据等等的闲话这里就不多说了,创建一个RESTful的目的在于产生下面的JSON格式数据,以便于我们在Android、Java、Python、jQuery等语言框架或者平台上可以调用,最主要的是可以直接用Ajax来产生更炫目的效果。

152 |
{
153 | "id": 1,
154 | "temperature": 14,
155 | "sensors1": 12,
156 | "sensors2": 12,
157 | "led1": 0
158 | }
159 | 160 | 161 | -------------------------------------------------------------------------------- /build/2.intro.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 一步步搭建物联网系统(教你设计物联网系统) 15 | 16 | 17 | 18 | 19 | 20 |

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

21 | 22 | 23 |
24 | 31 |
32 |

0.1 介绍

33 |

关于内容的选择,这是一个有意思的话题,因为我们很难判断不同的开发者用的是怎样的语言,用的是怎样的框架。

34 |

于是我们便自作主张地选择了那些适合于理论学习的语言、框架、硬件,去除掉其他一些我们不需要考虑的因素,如语法,复杂度等等。当然,这些语言、框架、硬件也是最流行的。

35 | 45 |

0.1.1 为什么没有C ?

46 |

C都不懂还跑过来干嘛

47 |

0.1.2 为什么不是JAVA ?

48 |

大有以下两个原因

49 | 53 |

0.2 如何阅读

54 |

这只是一个小小的建议,仅针对于在选择阅读上没有经验的读者。

55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |
当前状态建议
软件初学者从头阅读
硬件开发者从头阅读
没有web经验的开发者从第二部分开始
77 |

我们会在前面十章里简单介绍一些必要的基础知识,这些知识将会在后面我们构建物联网系统时用到。

78 | 79 | 80 | -------------------------------------------------------------------------------- /build/3.1.iot-coap.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 64 |
65 |

0.1 使用IoT-CoAP构建物联网

66 |

(注意:windows系统npm install失败时,需要自己建立一个C:and Settings[USERNAME]Data文件)

67 |
npm install iot-coap
68 |

1.新建index.js

69 |

注意: 如果已经存在一个index.js文件,请将下面内容添加到文件末尾(create index.js, and add)

70 |
var iotcoap         = require('iot-coap');
 71 | 
 72 | iotcoap.run();
 73 | iotcoap.rest.run();
74 |

注意:在db配置可以选择mongodb和sqlite3,替换所需要的数据库即可。(you can choice db on iot.js with ‘sqlite’ or ‘mongodb’)

75 |

2.创建iot.js

76 |
exports.config  = {
 77 |     "db_name": "iot.db",
 78 |     "mongodb_name": "iot",
 79 |     "mongodb_documents": "iot",
 80 |     "db": "mongodb",
 81 |     "table_name": "basic",
 82 |     "keys":[
 83 |         "id",
 84 |         "value",
 85 |         "sensors1",
 86 |         "sensors2"
 87 |     ],
 88 |     "db_table": "id integer primary key, value text, sensors1 float, sensors2 float",
 89 |     "mongodb_init":[
 90 |         {
 91 |             id: 1,
 92 |             value: "is id 1",
 93 |             sensors1: 19,
 94 |             sensors2: 20
 95 |         },
 96 |         {
 97 |             id: 2,
 98 |             value: "is id 2",
 99 |             sensors1: 20,
100 |             sensors2: 21
101 |         }
102 |     ],
103 |     "init_table":[
104 |         "insert or replace into basic (id,value,sensors1,sensors2) VALUES (1, 'is id 1', 19, 20);",
105 |         "insert or replace into basic (id,value,sensors1,sensors2) VALUES (2, 'is id 2', 20, 21);"
106 |     ],
107 |     "query_table":"select * from basic;",
108 |     "rest_url": "/id/:id",
109 |     "rest_post_url": "/",
110 |     "rest_port": 8848
111 | };
112 |

3.运行(run)

113 |
node index.js
114 |

show:

115 |
coap listening at coap://0.0.0.0:5683
116 | restify listening at http://0.0.0.0:8848
117 | 118 | 119 | -------------------------------------------------------------------------------- /build/3.2.mqtt.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 66 |
67 |

1 MQTT

68 |
69 |

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。

70 |
71 |

早在1999年,IBM的Andy Stanford-Clark博士以及Arcom公司ArlenNipper博士发明了MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)技术[1] 。据Andy Stanford-Clark博士称,MQTT将在今年和明年呈现爆炸式增长。

72 |

1.1 Nodejs MQTT

73 |
74 |

mqtt.js is a library for the MQTT protocol, written in JavaScript to be used in node.js.

75 |
76 |
var mqtt = require('mqtt')
77 | 
78 | client = mqtt.createClient(1883, 'localhost');
79 | 
80 | client.subscribe('presence');
81 | client.publish('presence', 'Hello mqtt');
82 | 
83 | client.on('message', function (topic, message) {
84 |   console.log(message);
85 | });
86 | 
87 | client.end();
88 | 89 | 90 | -------------------------------------------------------------------------------- /build/4.0.easyiot.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 72 |
73 |

1 简单物联网

74 |

到这时,我们算搭建了一个简单的REST服务了。接着我们可以简单的做一个最小的物联网系统,将我们的单片机、MCU等等连上网。

75 |
76 | 硬件结构图 77 |

硬件结构图

78 |
79 |

考虑到如果我们只是单一连接各个节点,那么系统的结构图,同下所示

80 |
81 | 全连接 82 |

全连接

83 |
84 |

下面的星形结构图类似于我们在接下来所要构建的系统

85 |
86 | 星形结构图 87 |

星形结构图

88 |
89 |

一个用于控制真实电器的硬件实物图

90 |
91 | 简单实物图 92 |

简单实物图

93 |
94 |

1.1 硬件通信

95 |

1.1.1 串口通信

96 |

Arduino与Raspberry Pi通过串口通信的方式实现通信,相互传输所需要的数据,Raspberry Pi将资源传于互联网上对应的接口,接口可以在互联网上被访问。Laravel框架构架于服务器之上,将Raspbery Pi获取过来的数据存储于MySQL数据,再以REST服务的方式共享数据,互联网上的其他设备便可以通过网络来访问这些设备。Ajax用于将后台的数据以不需要刷新的方式传递到网站前台,通过HighCharts框架显示给终端用户。

97 |

1.1.1.1 Python

98 |

1.在Windows中的串口通常是COM1,COM0等等

99 |
ser=serial.Serial("COM0",9600)
100 |

2.Mac OS系统中位于/dev目录下,名字类似于tty.usbmodem1451

101 |
    serial.Serial("/dev/tty.usbmodem1451",9600)
102 |

3.在Linux内核的系统中虚拟串口用的节点是ttyACM,位于/dev目录下。

103 |
    serial.Serial("/dev/ttyACM0",9600)
104 |
105 |

串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能 的电路,我们称为串行接口电路。

106 |
107 |

便是打开这个设备,以9600的速率传输数据。

108 |

程序框架如下所示:

109 |
110 | Raspberry Pi 111 |

Raspberry Pi

112 |
113 |

代码如下:

114 |
import json
115 | import urllib2
116 | import serial
117 | import time
118 | 
119 | url="http://www.xianuniversity.com/athome/1"
120 | 
121 | while 1:
122 |     try:
123 |         date=urllib2.urlopen(url)
124 |         result=json.load(date)
125 |         status=result[0]["led1"]
126 |         ser=serial.Serial("/dev/ttyACM0",9600)
127 |         if status==1 :
128 |             ser.write("1")
129 |         elif status==0:
130 |             ser.write("0")
131 |         time.sleep(1)
132 |     except urllib2.URLError:
133 |         print "Bad URL or timeout"
134 |
135 | python返回json数据 136 |

python返回json数据

137 |
138 |

系统还需要对上面的数据进行处理,只拿其中的结果

139 |
140 | python处理完后的结果 141 |

python处理完后的结果

142 |
143 |

当改变led的状态后,便可以得到下面的结果

144 |
145 | 改变状态后的结果 146 |

改变状态后的结果

147 |
148 |

1.1.1.2 Ruby

149 |

如果你用的是Ruby的话,可以尝试使用serialport

150 |

安装

151 |
sudo gem install serialport
152 |

代码大致如下

153 |
require 'serialport'
154 | sp = SerialPort.new "/dev/ACM0", 9600
155 | sp.write "1"
156 |

注意: 根据相关的系统修改相关的代码。

157 |

1.2 硬件

158 |

1.2.1 Arduino

159 |

这样我们在我们的Arduino上所要做的便是,读取串口的结果并控制IO口。

160 |
int ledPort=13;
161 | 
162 | void setup() {
163 |   Serial.begin(9600);
164 |   pinMode(ledPort,OUTPUT);
165 | }
166 | 
167 | int serialData;
168 | void loop() {
169 |   String inString = "";
170 |   while (Serial.available()> 0)
171 |   {
172 |     int inChar = Serial.read();
173 |     if (isDigit(inChar)) {
174 |       inString += (char)inChar; 
175 |     }
176 |     serialData=inString.toInt();
177 |     Serial.print(serialData);
178 |   }
179 |   if(serialData==1){
180 |     digitalWrite(ledPort,HIGH);
181 |   }else{
182 |     digitalWrite(ledPort,LOW);
183 |   }
184 | }
185 |

如果结果是1的话,就让13口为高电平,也就是让灯亮起来。

186 |

1.2.2 继电器

187 |
188 |

继电器(英文名称:relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。故在电路中起着自动调节、安全保护、转换电路等作用。

189 |
190 |

在这里我们可以默认为我们想要为单片机的5V电压控制220V的电器。

191 |

最后我们便可以通过些来控制灯的开和关。

192 | 193 | 194 | -------------------------------------------------------------------------------- /build/5.0.android.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 46 | 47 | 48 | 49 | 50 | 51 | 一步步搭建物联网系统(教你设计物联网系统) 52 | 53 | 54 | 55 | 56 | 57 |

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

58 | 59 | 60 |
61 | 69 |
70 |

1 Android简单示例

71 |

由于在某些嵌入式系统中使用的是Android系统,这里给出一个简单的Android App的示例,具体代码可以从clone自https://github.com/phodal/iot-android

72 |

代码说明,经过测试的版本有

73 | 77 |

机型有

78 | 84 |

应该可以在大部分的手机上工作。

85 |

1.1 调用Web Services GET

86 |

这里我们参考一篇文章来调用Web Services——Calling Web Services in Android using HttpClient

87 |

1.1.1 创建RESTClient

88 |

在这里我们首先会定义四个REST方法GET、POST、PUT、DELETE

89 |
public void Execute(RequestMethod method) throws Exception {
 90 |     switch (method) {
 91 |     case GET: {
 92 |         // add parameters
 93 |         String combinedParams = "";
 94 |         if (!params.isEmpty()) {
 95 |             combinedParams += "?";
 96 |             for (NameValuePair p : params) {
 97 |                 String paramString = p.getName() + "="
 98 |                         + URLEncoder.encode(p.getValue(), HTTP.UTF_8);
 99 |                 if (combinedParams.length() > 1) {
100 |                     combinedParams += "&" + paramString;
101 |                 } else {
102 |                     combinedParams += paramString;
103 |                 }
104 |             }
105 |         }
106 | 
107 |         HttpGet request = new HttpGet(url + combinedParams);
108 |         request.addHeader("Accept-Encoding", "gzip");
109 | 
110 |         // add headers
111 |         for (NameValuePair h : headers) {
112 |             request.addHeader(h.getName(), h.getValue());
113 |         }
114 | 
115 |         executeRequest(request, url);
116 |         break;
117 |     }
118 |     case POST: {
119 |         HttpPost request = new HttpPost(url);
120 |         request.addHeader("Accept-Encoding", "gzip");
121 | 
122 |         // add headers
123 |         for (NameValuePair h : headers) {
124 |             request.addHeader(h.getName(), h.getValue());
125 |         }
126 |         if (!data.equals("")) {
127 |             request.setEntity(new StringEntity(data, HTTP.UTF_8));
128 |         }
129 | 
130 |         if (!params.isEmpty()) {
131 |             request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
132 |         }
133 | 
134 |         executeRequest(request, url);
135 |         break;
136 |     }
137 |     case PUT: {
138 |         HttpPut request = new HttpPut(url);
139 |         request.addHeader("Accept-Encoding", "gzip");
140 | 
141 |         // add headers
142 |         for (NameValuePair h : headers) {
143 |             request.addHeader(h.getName(), h.getValue());
144 |         }
145 |         if (!data.equals("")) {
146 |             request.setEntity(new StringEntity(data, HTTP.UTF_8));
147 |         }
148 | 
149 |         if (!params.isEmpty()) {
150 |             request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
151 |         }
152 | 
153 |         executeRequest(request, url);
154 |         break;
155 |     }
156 |     case DELETE: {
157 |         HttpDelete request = new HttpDelete(url);
158 |         request.addHeader("Accept-Encoding", "gzip");
159 | 
160 |         // add headers
161 |         for (NameValuePair h : headers) {
162 |             request.addHeader(h.getName(), h.getValue());
163 |         }
164 | 
165 |         executeRequest(request, url);
166 |         break;
167 |     }
168 |     }
169 | }
170 |

这四个方法最后都执行executeRequest来获取响应结果。

171 |
protected void executeRequest(HttpUriRequest request, String url) {
172 | 
173 |         HttpParams httpParameters = new BasicHttpParams();
174 |         HttpConnectionParams.setConnectionTimeout(httpParameters,
175 |                 timeoutConnection);
176 |         HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
177 |         
178 |         HttpProtocolParams.setUseExpectContinue(httpParameters, false);
179 |         request.setParams(httpParameters);
180 |         
181 |         setOauth(request);
182 |         
183 |         DefaultHttpClient client = new DefaultHttpClient();
184 | 
185 |         HttpResponse httpResponse;
186 | 
187 |         try {
188 |             httpResponse = client.execute(request);
189 |             responseCode = httpResponse.getStatusLine().getStatusCode();
190 |             message = httpResponse.getStatusLine().getReasonPhrase();
191 | 
192 |             HttpEntity entity = httpResponse.getEntity();
193 | 
194 |             if (entity != null) {
195 |                 InputStream instream = httpResponse.getEntity().getContent();
196 |                 Header contentEncoding = httpResponse
197 |                         .getFirstHeader("Content-Encoding");
198 | 
199 |                 if (contentEncoding != null
200 |                         && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
201 |                     instream = new GZIPInputStream(instream);
202 |                 }
203 | 
204 |                 // instream = entity.getContent();
205 |                 response = convertStreamToString(instream);
206 | 
207 |                 // Closing the input stream will trigger connection release
208 |                 instream.close();
209 |             }
210 | 
211 |         } catch (ClientProtocolException e) {
212 |             client.getConnectionManager().shutdown();
213 |             e.printStackTrace();
214 |         } catch (IOException e) {
215 |             client.getConnectionManager().shutdown();
216 |             e.printStackTrace();
217 |         }
218 |     }
219 |

接着,我们便可以执行getResponse()函数来获取结果。

220 |

1.2 使用REST Client获取结果

221 |

使用RESTClient时,便可以用下面的示例

222 |
RestClient client = new RestClient(tUrl);
223 | try {
224 |     client.Execute(RequestMethod.GET);
225 |     if (client.getResponseCode() != 200) {
226 |         //do something
227 |     }
228 |     //JSONArray jArray = new JSONArray(client.getResponse());
229 | } catch (Exception e) {
230 |     //do something
231 | }
232 |

而这时,我们只需要对相应的数据进行处理就可以了,如

233 |
JSONArray jArray = new JSONArray(client.getResponse());
234 | JSONObject jObj=jArray.getJSONObject(0);
235 | vshow.setText(jObj.toString());
236 | 
237 | outputJSON(jObj);
238 |

将他转换为String,接着在Android端上显示最后的结果。

239 | 240 | 241 | -------------------------------------------------------------------------------- /build/designiot.epub: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/build/designiot.epub -------------------------------------------------------------------------------- /build/qa.md.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 一步步搭建物联网系统(教你设计物联网系统) 15 | 16 | 17 | 18 | 19 | 20 |

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

21 | 22 | 23 |
24 | 30 |
31 |

1 尾声

32 |

1.1

33 |

1.2 其他

34 |

意见及建议: https://github.com/phodal/designiot/issues

35 |

邮箱: h@phodal.com

36 | 37 | 38 | -------------------------------------------------------------------------------- /designiot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/designiot.jpg -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /images/88x31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/88x31.png -------------------------------------------------------------------------------- /images/arch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/arch.jpeg -------------------------------------------------------------------------------- /images/arduino.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/arduino.png -------------------------------------------------------------------------------- /images/box-model.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/box-model.gif -------------------------------------------------------------------------------- /images/change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/change.png -------------------------------------------------------------------------------- /images/dom_tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/dom_tree.jpg -------------------------------------------------------------------------------- /images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/edit.png -------------------------------------------------------------------------------- /images/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/flow.png -------------------------------------------------------------------------------- /images/fullconnected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/fullconnected.png -------------------------------------------------------------------------------- /images/getjson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/getjson.png -------------------------------------------------------------------------------- /images/gnu_linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/gnu_linux.png -------------------------------------------------------------------------------- /images/gpio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/gpio.png -------------------------------------------------------------------------------- /images/hardware.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/hardware.jpg -------------------------------------------------------------------------------- /images/hwcnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/hwcnt.png -------------------------------------------------------------------------------- /images/linux_kernel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/linux_kernel.jpg -------------------------------------------------------------------------------- /images/lnmp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/lnmp.gif -------------------------------------------------------------------------------- /images/lnmp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/lnmp.jpg -------------------------------------------------------------------------------- /images/nostyle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/nostyle.png -------------------------------------------------------------------------------- /images/origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/origin.png -------------------------------------------------------------------------------- /images/pm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/pm.png -------------------------------------------------------------------------------- /images/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/python.png -------------------------------------------------------------------------------- /images/raspberrypi_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/raspberrypi_flow.png -------------------------------------------------------------------------------- /images/redfonts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/redfonts.png -------------------------------------------------------------------------------- /images/rpi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/rpi.jpg -------------------------------------------------------------------------------- /images/shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/shell.png -------------------------------------------------------------------------------- /images/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/star.png -------------------------------------------------------------------------------- /images/temperture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/temperture.png -------------------------------------------------------------------------------- /images/uno.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/uno.png -------------------------------------------------------------------------------- /images/webkitflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/webkitflow.png -------------------------------------------------------------------------------- /images/xml-vs-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/designiot/0b8332b85ed6fe10d81d8092188bc39da3610807/images/xml-vs-json.png -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | ``` -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /template/head-chapter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 一步步搭建物联网系统(教你设计物联网系统) 4 | 5 | 6 | 7 | 8 | 9 |

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

10 | 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /template/headpdf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 一步步搭建物联网系统(教你设计物联网系统) 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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} --------------------------------------------------------------------------------