├── iot.doc ├── iot.pdf ├── iot.docx ├── struct.bmp ├── struct.dot ├── Makefile ├── README.md ├── template.tex ├── struct.ps └── iot.md /iot.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iot-works/iot-doc/HEAD/iot.doc -------------------------------------------------------------------------------- /iot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iot-works/iot-doc/HEAD/iot.pdf -------------------------------------------------------------------------------- /iot.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iot-works/iot-doc/HEAD/iot.docx -------------------------------------------------------------------------------- /struct.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iot-works/iot-doc/HEAD/struct.bmp -------------------------------------------------------------------------------- /struct.dot: -------------------------------------------------------------------------------- 1 | digraph G{ 2 | compound=true; 3 | 4 | subgraph cluster0{ 5 | RaspberryPi->Hardware; 6 | Hardware->RaspberryPi[label="Serial Commucation"]; 7 | } 8 | subgraph cluster1{ 9 | Server->RaspberryPi [label="GET/POST"]; 10 | RaspberryPi->Server; 11 | Browser->Server [label="CRUD"]; 12 | Server->Browser [label="Ajax"]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: docx 2 | 3 | docx: 4 | sed 's/
/}/g' iot2.md > iot3.md
6 | sed 's/<\/code><\/pre>/~~~~ /g' iot3.md > iot2.md
7 | pandoc iot2.md -o iot.docx --toc --smart --highlight-style=pygments
8 | rm iot2.md iot3.md
9 |
10 | pdf:
11 | sed 's//}/g' iot2.md > iot3.md
13 | sed 's/<\/code><\/pre>/~~~~ /g' iot3.md > iot2.md
14 | sed 's/.bmp/.ps/g' iot2.md > iot3.md
15 | pandoc --template=template.tex --latex-engine=xelatex iot3.md -o iot.pdf --toc --smart --highlight-style=pygments
16 | @echo "remove the iot temp file"
17 | rm iot2.md iot3.md
18 |
19 | img:
20 | dot struct.dot -Tbmp -o struct.bmp
21 | dot struct.dot -Tps -o struct.ps
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##安装pandoc##
2 | 这是一个痛苦而又复杂的过程,当然也可以直接下载[Pandoc][0]
3 | [0]:http://code.google.com/p/pandoc/downloads/list
4 |
5 | ###安装ghc###
6 | port安装ghc
7 |
8 | sudo port install ghc
9 |
10 | homebrew安装ghc
11 |
12 | brew install ghc
13 |
14 | ###编译cabal###
15 |
16 | Common Architecture for Building Applications and Libraries2
17 |
18 | Cabal是Haskell用于构建应用程序和库的公共架构。
19 |
20 | 简单的来说它是haskell的包管理,和上面的port、brew 命令类似。
21 |
22 | 下载地址[http://haskell.org/cabal/][1]
23 |
24 | [1]:http://haskell.org/cabal/
25 |
26 | 解压后
27 |
28 | ghc --make Setup.hs
29 | ./Setup configure
30 | ./Setup build
31 | sudo ./Setup install
32 |
33 | ###安装cabal###
34 |
35 | 安装之前我们需要更新
36 |
37 | cabal update
38 |
39 | 安装pandoc
40 |
41 | cabal install pandoc
42 |
43 | 添加到PATH
44 |
45 | export PATH=/Users/fdhuang/.cabal/bin:$PATH
46 |
47 | #markdown 转doc#
48 |
49 | pandoc iot.md -o iot.docx
50 |
51 | #markdown 转pdf#
52 | 这里只针对于安装了mactex
53 |
54 | ##安装mactex##
55 |
56 | 下载地址:
57 |
58 | [http://mirror.ctan.org/systems/mac/mactex/mactex-basic.pkg][2]
59 |
60 | [2]:http://mirror.ctan.org/systems/mac/mactex/mactex-basic.pkg
61 |
62 |
63 | ##markdown转pdf##
64 |
65 | 不含中文时
66 |
67 | pandoc doc.pandoc doc.pdf
68 |
69 | 含有中文时的简单作法
70 |
71 | pandoc --latex-engine=xelatex iot.md -o iot.pdf -V mainfont="SimSun"
72 |
73 |
--------------------------------------------------------------------------------
/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{amssymb,amsmath}
15 | \usepackage{ifxetex,ifluatex}
16 | \usepackage{fixltx2e} % provides \textsubscript
17 | % use upquote if available, for straight quotes in verbatim environments
18 | \IfFileExists{upquote.sty}{\usepackage{upquote}}{}
19 | \ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
20 | \usepackage[utf8]{inputenc}
21 | $if(euro)$
22 | \usepackage{eurosym}
23 | $endif$
24 | \else % if luatex or xelatex
25 | \usepackage{fontspec} % 允許設定字體
26 | \usepackage{xeCJK} % 分開設置中英文字型
27 | \setCJKmainfont{STSong} % 設定中文字型
28 | \setmainfont{Georgia} % 設定英文字型
29 | \setromanfont{Georgia} % 字型
30 | \setmonofont{Courier New}
31 | \linespread{1.2}\selectfont % 行距
32 | \XeTeXlinebreaklocale "zh" % 針對中文自動換行
33 | \XeTeXlinebreakskip = 0pt plus 1pt % 字與字之間加入0pt至1pt的間距,確保左右對整齊
34 | \parindent 0em % 段落縮進
35 | \setlength{\parskip}{20pt} % 段落之間的距離
36 | \ifxetex
37 | \usepackage{xltxtra,xunicode}
38 | \fi
39 | \defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase}
40 | \newcommand{\euro}{€}
41 | $if(mainfont)$
42 | \setmainfont{$mainfont$}
43 | $endif$
44 | $if(sansfont)$
45 | \setsansfont{$sansfont$}
46 | $endif$
47 | $if(monofont)$
48 | \setmonofont{$monofont$}
49 | $endif$
50 | $if(mathfont)$
51 | \setmathfont{$mathfont$}
52 | $endif$
53 | \fi
54 | % use microtype if available
55 | \IfFileExists{microtype.sty}{\usepackage{microtype}}{}
56 | $if(geometry)$
57 | \usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
58 | $endif$
59 | $if(natbib)$
60 | \usepackage{natbib}
61 | \bibliographystyle{plainnat}
62 | $endif$
63 | $if(biblatex)$
64 | \usepackage{biblatex}
65 | $if(biblio-files)$
66 | \bibliography{$biblio-files$}
67 | $endif$
68 | $endif$
69 | $if(listings)$
70 | \usepackage{listings}
71 | $endif$
72 | $if(lhs)$
73 | \lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
74 | $endif$
75 | $if(highlighting-macros)$
76 | $highlighting-macros$
77 | $endif$
78 | $if(verbatim-in-note)$
79 | \usepackage{fancyvrb}
80 | $endif$
81 | $if(tables)$
82 | \usepackage{longtable}
83 | $endif$
84 |
85 | \usepackage{graphicx}
86 | % We will generate all images so they have a width \maxwidth. This means
87 | % that they will get their normal width if they fit onto the page, but
88 | % are scaled down if they would overflow the margins.
89 | \makeatletter
90 | \def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth
91 | \else\Gin@nat@width\fi}
92 | \makeatother
93 | \let\Oldincludegraphics\includegraphics
94 | \renewcommand{\includegraphics}[1]{\Oldincludegraphics[width=\maxwidth]{#1}}
95 |
96 | \ifxetex
97 | \usepackage[setpagesize=false, % page size defined by xetex
98 | unicode=false, % unicode breaks when used with xetex
99 | xetex]{hyperref}
100 | \else
101 | \usepackage[unicode=true]{hyperref}
102 | \fi
103 | \hypersetup{breaklinks=true,
104 | bookmarks=true,
105 | pdfauthor={$author-meta$},
106 | pdftitle={$title-meta$},
107 | colorlinks=true,
108 | urlcolor=$if(urlcolor)$$urlcolor$$else$blue$endif$,
109 | linkcolor=$if(linkcolor)$$linkcolor$$else$magenta$endif$,
110 | pdfborder={0 0 0}}
111 | \urlstyle{same} % don't use monospace font for urls
112 | $if(links-as-notes)$
113 | % Make links footnotes instead of hotlinks:
114 | \renewcommand{\href}[2]{#2\footnote{\url{#1}}}
115 | $endif$
116 | $if(strikeout)$
117 | \usepackage[normalem]{ulem}
118 | % avoid problems with \sout in headers with hyperref:
119 | \pdfstringdefDisableCommands{\renewcommand{\sout}{}}
120 | $endif$
121 | \setlength{\parindent}{0pt}
122 | %\setlength{\parskip}{6pt plus 2pt minus 1pt}
123 | \setlength{\emergencystretch}{3em} % prevent overfull lines
124 |
125 | \title{\huge 基于REST服务的最小物联网系统设计} % 設置標題,使用巨大字體
126 | \author{Phodal Huang} % 設置作者
127 | \date{February 2014} % 設置日期
128 | \usepackage{titling}
129 | \setlength{\droptitle}{-8em} % 將標題移動至頁面的上面
130 |
131 | \usepackage{fancyhdr}
132 | \usepackage{lastpage}
133 | \pagestyle{fancyplain}
134 |
135 | $if(numbersections)$
136 | \setcounter{secnumdepth}{5}
137 | $else$
138 | \setcounter{secnumdepth}{0}
139 | $endif$
140 | $if(verbatim-in-note)$
141 | \VerbatimFootnotes % allows verbatim text in footnotes
142 | $endif$
143 | $if(lang)$
144 | \ifxetex
145 | \usepackage{polyglossia}
146 | \setmainlanguage{$mainlang$}
147 | \else
148 | \usepackage[$lang$]{babel}
149 | \fi
150 | $endif$
151 | $for(header-includes)$
152 | $header-includes$
153 | $endfor$
154 |
155 | $if(title)$
156 | \title{$title$}
157 | $endif$
158 | \author{$for(author)$$author$$sep$ \and $endfor$}
159 | \date{$date$}
160 |
161 | %%%%%% 设置字号 %%%%%%
162 | \newcommand{\chuhao}{\fontsize{42pt}{\baselineskip}\selectfont}
163 | \newcommand{\xiaochuhao}{\fontsize{36pt}{\baselineskip}\selectfont}
164 | \newcommand{\yihao}{\fontsize{28pt}{\baselineskip}\selectfont}
165 | \newcommand{\erhao}{\fontsize{21pt}{\baselineskip}\selectfont}
166 | \newcommand{\xiaoerhao}{\fontsize{18pt}{\baselineskip}\selectfont}
167 | \newcommand{\sanhao}{\fontsize{15.75pt}{\baselineskip}\selectfont}
168 | \newcommand{\sihao}{\fontsize{14pt}{\baselineskip}\selectfont}
169 | \newcommand{\xiaosihao}{\fontsize{12pt}{\baselineskip}\selectfont}
170 | \newcommand{\wuhao}{\fontsize{10.5pt}{\baselineskip}\selectfont}
171 | \newcommand{\xiaowuhao}{\fontsize{9pt}{\baselineskip}\selectfont}
172 | \newcommand{\liuhao}{\fontsize{7.875pt}{\baselineskip}\selectfont}
173 | \newcommand{\qihao}{\fontsize{5.25pt}{\baselineskip}\selectfont}
174 |
175 | %%%% 设置 section 属性 %%%%
176 | \makeatletter
177 | \renewcommand\section{\@startsection{section}{1}{\z@}%
178 | {-1.5ex \@plus -.5ex \@minus -.2ex}%
179 | {.5ex \@plus .1ex}%
180 | {\normalfont\sihao\CJKfamily{STHeiti}}}
181 | \makeatother
182 |
183 | %%%% 设置 subsection 属性 %%%%
184 | \makeatletter
185 | \renewcommand\subsection{\@startsection{subsection}{1}{\z@}%
186 | {-1.25ex \@plus -.5ex \@minus -.2ex}%
187 | {.4ex \@plus .1ex}%
188 | {\normalfont\xiaosihao\CJKfamily{STHeiti}}}
189 | \makeatother
190 |
191 | %%%% 设置 subsubsection 属性 %%%%
192 | \makeatletter
193 | \renewcommand\subsubsection{\@startsection{subsubsection}{1}{\z@}%
194 | {-1ex \@plus -.5ex \@minus -.2ex}%
195 | {.3ex \@plus .1ex}%
196 | {\normalfont\xiaosihao\CJKfamily{STHeiti}}}
197 | \makeatother
198 |
199 | %%%% 段落首行缩进两个字 %%%%
200 | \makeatletter
201 | \let\@afterindentfalse\@afterindenttrue
202 | \@afterindenttrue
203 | \makeatother
204 | \setlength{\parindent}{2em} %中文缩进两个汉字位
205 |
206 |
207 | %%%% 下面的命令重定义页面边距,使其符合中文刊物习惯 %%%%
208 | \addtolength{\topmargin}{-2pt}
209 | \setlength{\oddsidemargin}{0.63cm} % 3.17cm - 1 inch
210 | \setlength{\evensidemargin}{\oddsidemargin}
211 | \setlength{\textwidth}{14.66cm}
212 | \setlength{\textheight}{24.00cm} % 24.62
213 |
214 | %%%% 下面的命令设置行间距与段落间距 %%%%
215 | \linespread{1.4}
216 | % \setlength{\parskip}{1ex}
217 | \setlength{\parskip}{0.5\baselineskip}
218 |
219 |
220 | \begin{document}
221 | %%%% 定理类环境的定义 %%%%
222 | \newtheorem{example}{例} % 整体编号
223 | \newtheorem{algorithm}{算法}
224 | \newtheorem{theorem}{定理}[section] % 按 section 编号
225 | \newtheorem{definition}{定义}
226 | \newtheorem{axiom}{公理}
227 | \newtheorem{property}{性质}
228 | \newtheorem{proposition}{命题}
229 | \newtheorem{lemma}{引理}
230 | \newtheorem{corollary}{推论}
231 | \newtheorem{remark}{注解}
232 | \newtheorem{condition}{条件}
233 | \newtheorem{conclusion}{结论}
234 | \newtheorem{assumption}{假设}
235 |
236 | %%%% 重定义 %%%%
237 | \renewcommand{\contentsname}{目录} % 将Contents改为目录
238 | \renewcommand{\abstractname}{摘要} % 将Abstract改为摘要
239 | \renewcommand{\refname}{参考文献} % 将References改为参考文献
240 | \renewcommand{\indexname}{索引}
241 | \renewcommand{\figurename}{图}
242 | \renewcommand{\tablename}{表}
243 | \renewcommand{\appendixname}{附录}
244 |
245 | \maketitle
246 |
247 | $for(include-before)$
248 | $include-before$
249 |
250 | $endfor$
251 | $if(toc)$
252 | {
253 | \hypersetup{linkcolor=black}
254 | \setcounter{tocdepth}{$toc-depth$}
255 | \tableofcontents
256 | }
257 | \newpage
258 | $endif$
259 | $body$
260 |
261 | $if(natbib)$
262 | $if(biblio-files)$
263 | $if(biblio-title)$
264 | $if(book-class)$
265 | \renewcommand\bibname{$biblio-title$}
266 | $else$
267 | \renewcommand\refname{$biblio-title$}
268 | $endif$
269 | $endif$
270 | \bibliography{$biblio-files$}
271 |
272 | $endif$
273 | $endif$
274 | $if(biblatex)$
275 | \printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
276 |
277 | $endif$
278 | $for(include-after)$
279 | $include-after$
280 |
281 | $endfor$
282 | \end{document}
283 |
--------------------------------------------------------------------------------
/struct.ps:
--------------------------------------------------------------------------------
1 | %!PS-Adobe-3.0
2 | %%Creator: graphviz version 2.34.0 (20140103.0956)
3 | %%Title: G
4 | %%Pages: (atend)
5 | %%BoundingBox: (atend)
6 | %%EndComments
7 | save
8 | %%BeginProlog
9 | /DotDict 200 dict def
10 | DotDict begin
11 |
12 | /setupLatin1 {
13 | mark
14 | /EncodingVector 256 array def
15 | EncodingVector 0
16 |
17 | ISOLatin1Encoding 0 255 getinterval putinterval
18 | EncodingVector 45 /hyphen put
19 |
20 | % Set up ISO Latin 1 character encoding
21 | /starnetISO {
22 | dup dup findfont dup length dict begin
23 | { 1 index /FID ne { def }{ pop pop } ifelse
24 | } forall
25 | /Encoding EncodingVector def
26 | currentdict end definefont
27 | } def
28 | /Times-Roman starnetISO def
29 | /Times-Italic starnetISO def
30 | /Times-Bold starnetISO def
31 | /Times-BoldItalic starnetISO def
32 | /Helvetica starnetISO def
33 | /Helvetica-Oblique starnetISO def
34 | /Helvetica-Bold starnetISO def
35 | /Helvetica-BoldOblique starnetISO def
36 | /Courier starnetISO def
37 | /Courier-Oblique starnetISO def
38 | /Courier-Bold starnetISO def
39 | /Courier-BoldOblique starnetISO def
40 | cleartomark
41 | } bind def
42 |
43 | %%BeginResource: procset graphviz 0 0
44 | /coord-font-family /Times-Roman def
45 | /default-font-family /Times-Roman def
46 | /coordfont coord-font-family findfont 8 scalefont def
47 |
48 | /InvScaleFactor 1.0 def
49 | /set_scale {
50 | dup 1 exch div /InvScaleFactor exch def
51 | scale
52 | } bind def
53 |
54 | % styles
55 | /solid { [] 0 setdash } bind def
56 | /dashed { [9 InvScaleFactor mul dup ] 0 setdash } bind def
57 | /dotted { [1 InvScaleFactor mul 6 InvScaleFactor mul] 0 setdash } bind def
58 | /invis {/fill {newpath} def /stroke {newpath} def /show {pop newpath} def} bind def
59 | /bold { 2 setlinewidth } bind def
60 | /filled { } bind def
61 | /unfilled { } bind def
62 | /rounded { } bind def
63 | /diagonals { } bind def
64 | /tapered { } bind def
65 |
66 | % hooks for setting color
67 | /nodecolor { sethsbcolor } bind def
68 | /edgecolor { sethsbcolor } bind def
69 | /graphcolor { sethsbcolor } bind def
70 | /nopcolor {pop pop pop} bind def
71 |
72 | /beginpage { % i j npages
73 | /npages exch def
74 | /j exch def
75 | /i exch def
76 | /str 10 string def
77 | npages 1 gt {
78 | gsave
79 | coordfont setfont
80 | 0 0 moveto
81 | (\() show i str cvs show (,) show j str cvs show (\)) show
82 | grestore
83 | } if
84 | } bind def
85 |
86 | /set_font {
87 | findfont exch
88 | scalefont setfont
89 | } def
90 |
91 | % draw text fitted to its expected width
92 | /alignedtext { % width text
93 | /text exch def
94 | /width exch def
95 | gsave
96 | width 0 gt {
97 | [] 0 setdash
98 | text stringwidth pop width exch sub text length div 0 text ashow
99 | } if
100 | grestore
101 | } def
102 |
103 | /boxprim { % xcorner ycorner xsize ysize
104 | 4 2 roll
105 | moveto
106 | 2 copy
107 | exch 0 rlineto
108 | 0 exch rlineto
109 | pop neg 0 rlineto
110 | closepath
111 | } bind def
112 |
113 | /ellipse_path {
114 | /ry exch def
115 | /rx exch def
116 | /y exch def
117 | /x exch def
118 | matrix currentmatrix
119 | newpath
120 | x y translate
121 | rx ry scale
122 | 0 0 1 0 360 arc
123 | setmatrix
124 | } bind def
125 |
126 | /endpage { showpage } bind def
127 | /showpage { } def
128 |
129 | /layercolorseq
130 | [ % layer color sequence - darkest to lightest
131 | [0 0 0]
132 | [.2 .8 .8]
133 | [.4 .8 .8]
134 | [.6 .8 .8]
135 | [.8 .8 .8]
136 | ]
137 | def
138 |
139 | /layerlen layercolorseq length def
140 |
141 | /setlayer {/maxlayer exch def /curlayer exch def
142 | layercolorseq curlayer 1 sub layerlen mod get
143 | aload pop sethsbcolor
144 | /nodecolor {nopcolor} def
145 | /edgecolor {nopcolor} def
146 | /graphcolor {nopcolor} def
147 | } bind def
148 |
149 | /onlayer { curlayer ne {invis} if } def
150 |
151 | /onlayers {
152 | /myupper exch def
153 | /mylower exch def
154 | curlayer mylower lt
155 | curlayer myupper gt
156 | or
157 | {invis} if
158 | } def
159 |
160 | /curlayer 0 def
161 |
162 | %%EndResource
163 | %%EndProlog
164 | %%BeginSetup
165 | 14 default-font-family set_font
166 | 1 setmiterlimit
167 | % /arrowlength 10 def
168 | % /arrowwidth 5 def
169 |
170 | % make sure pdfmark is harmless for PS-interpreters other than Distiller
171 | /pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse
172 | % make '<<' and '>>' safe on PS Level 1 devices
173 | /languagelevel where {pop languagelevel}{1} ifelse
174 | 2 lt {
175 | userdict (<<) cvn ([) cvn load put
176 | userdict (>>) cvn ([) cvn load put
177 | } if
178 |
179 | %%EndSetup
180 | setupLatin1
181 | %%Page: 1 1
182 | %%PageBoundingBox: 36 36 347 292
183 | %%PageOrientation: Portrait
184 | 0 0 1 beginpage
185 | gsave
186 | 36 36 311 256 boxprim clip newpath
187 | 1 1 set_scale 0 rotate 40 40 translate
188 | % cluster0
189 | gsave
190 | 1 setlinewidth
191 | 0 0 0 graphcolor
192 | newpath 8 98 moveto
193 | 8 240 lineto
194 | 164 240 lineto
195 | 164 98 lineto
196 | closepath stroke
197 | grestore
198 | % cluster1
199 | gsave
200 | 1 setlinewidth
201 | 0 0 0 graphcolor
202 | newpath 172 8 moveto
203 | 172 150 lineto
204 | 295 150 lineto
205 | 295 8 lineto
206 | closepath stroke
207 | grestore
208 | % RaspberryPi
209 | gsave
210 | 1 setlinewidth
211 | 0 0 0 nodecolor
212 | 86 214 58.17 18 ellipse_path stroke
213 | 0 0 0 nodecolor
214 | 14 /Times-Roman set_font
215 | 51.39 208.4 moveto 69.21 (RaspberryPi) alignedtext
216 | grestore
217 | % Hardware
218 | gsave
219 | 1 setlinewidth
220 | 0 0 0 nodecolor
221 | 65 124 49.15 18 ellipse_path stroke
222 | 0 0 0 nodecolor
223 | 14 /Times-Roman set_font
224 | 37.41 118.4 moveto 55.19 (Hardware) alignedtext
225 | grestore
226 | % RaspberryPi->Hardware
227 | gsave
228 | 1 setlinewidth
229 | 0 0 0 edgecolor
230 | newpath 47.5 200.3 moveto
231 | 37.45 195.04 27.81 187.8 22 178 curveto
232 | 15.34 166.76 22.39 155.38 32.58 146.05 curveto
233 | stroke
234 | 0 0 0 edgecolor
235 | newpath 34.87 148.7 moveto
236 | 40.4 139.66 lineto
237 | 30.44 143.28 lineto
238 | closepath fill
239 | 1 setlinewidth
240 | solid
241 | 0 0 0 edgecolor
242 | newpath 34.87 148.7 moveto
243 | 40.4 139.66 lineto
244 | 30.44 143.28 lineto
245 | closepath stroke
246 | grestore
247 | % Server
248 | gsave
249 | 1 setlinewidth
250 | 0 0 0 nodecolor
251 | 216 124 36.36 18 ellipse_path stroke
252 | 0 0 0 nodecolor
253 | 14 /Times-Roman set_font
254 | 197.73 118.4 moveto 36.54 (Server) alignedtext
255 | grestore
256 | % RaspberryPi->Server
257 | gsave
258 | 1 setlinewidth
259 | 0 0 0 edgecolor
260 | newpath 122.31 199.67 moveto
261 | 135.68 193.96 150.57 186.61 163 178 curveto
262 | 174.98 169.7 186.63 158.51 195.94 148.55 curveto
263 | stroke
264 | 0 0 0 edgecolor
265 | newpath 198.74 150.67 moveto
266 | 202.87 140.91 lineto
267 | 193.56 145.97 lineto
268 | closepath fill
269 | 1 setlinewidth
270 | solid
271 | 0 0 0 edgecolor
272 | newpath 198.74 150.67 moveto
273 | 202.87 140.91 lineto
274 | 193.56 145.97 lineto
275 | closepath stroke
276 | grestore
277 | % Hardware->RaspberryPi
278 | gsave
279 | 1 setlinewidth
280 | 0 0 0 edgecolor
281 | newpath 53.3 141.55 moveto
282 | 47.3 152.16 42.27 166.13 47.52 178 curveto
283 | 49.47 182.41 52.29 186.51 55.52 190.23 curveto
284 | stroke
285 | 0 0 0 edgecolor
286 | newpath 53.05 192.71 moveto
287 | 62.59 197.31 lineto
288 | 58 187.76 lineto
289 | closepath fill
290 | 1 setlinewidth
291 | solid
292 | 0 0 0 edgecolor
293 | newpath 53.05 192.71 moveto
294 | 62.59 197.31 lineto
295 | 58 187.76 lineto
296 | closepath stroke
297 | 0 0 0 edgecolor
298 | 14 /Times-Roman set_font
299 | 48 163.4 moveto 115.48 (Serial Commucation) alignedtext
300 | grestore
301 | % Server->RaspberryPi
302 | gsave
303 | 1 setlinewidth
304 | 0 0 0 edgecolor
305 | newpath 211.81 141.96 moveto
306 | 208.13 153.58 201.65 168.55 191 178 curveto
307 | 178.44 189.14 162.23 196.76 146.31 201.95 curveto
308 | stroke
309 | 0 0 0 edgecolor
310 | newpath 145.06 198.67 moveto
311 | 136.48 204.89 lineto
312 | 147.06 205.38 lineto
313 | closepath fill
314 | 1 setlinewidth
315 | solid
316 | 0 0 0 edgecolor
317 | newpath 145.06 198.67 moveto
318 | 136.48 204.89 lineto
319 | 147.06 205.38 lineto
320 | closepath stroke
321 | 0 0 0 edgecolor
322 | 14 /Times-Roman set_font
323 | 205 163.4 moveto 65.34 (GET/POST) alignedtext
324 | grestore
325 | % Browser
326 | gsave
327 | 1 setlinewidth
328 | 0 0 0 nodecolor
329 | 233 34 43.14 18 ellipse_path stroke
330 | 0 0 0 nodecolor
331 | 14 /Times-Roman set_font
332 | 209.28 28.4 moveto 47.43 (Browser) alignedtext
333 | grestore
334 | % Server->Browser
335 | gsave
336 | 1 setlinewidth
337 | 0 0 0 edgecolor
338 | newpath 202.81 107.11 moveto
339 | 195.68 96.52 189.36 82.34 194.79 70 curveto
340 | 196.91 65.18 200.05 60.74 203.65 56.75 curveto
341 | stroke
342 | 0 0 0 edgecolor
343 | newpath 206.21 59.14 moveto
344 | 210.95 49.66 lineto
345 | 201.34 54.11 lineto
346 | closepath fill
347 | 1 setlinewidth
348 | solid
349 | 0 0 0 edgecolor
350 | newpath 206.21 59.14 moveto
351 | 210.95 49.66 lineto
352 | 201.34 54.11 lineto
353 | closepath stroke
354 | 0 0 0 edgecolor
355 | 14 /Times-Roman set_font
356 | 195 73.4 moveto 27.21 (Ajax) alignedtext
357 | grestore
358 | % Browser->Server
359 | gsave
360 | 1 setlinewidth
361 | 0 0 0 edgecolor
362 | newpath 231.37 52.29 moveto
363 | 230.22 62.7 228.45 76.19 226 88 curveto
364 | 225.44 90.69 224.78 93.48 224.08 96.25 curveto
365 | stroke
366 | 0 0 0 edgecolor
367 | newpath 220.66 95.47 moveto
368 | 221.39 106.04 lineto
369 | 227.41 97.32 lineto
370 | closepath fill
371 | 1 setlinewidth
372 | solid
373 | 0 0 0 edgecolor
374 | newpath 220.66 95.47 moveto
375 | 221.39 106.04 lineto
376 | 227.41 97.32 lineto
377 | closepath stroke
378 | 0 0 0 edgecolor
379 | 14 /Times-Roman set_font
380 | 229 73.4 moveto 38.9 (CRUD) alignedtext
381 | grestore
382 | endpage
383 | showpage
384 | grestore
385 | %%PageTrailer
386 | %%EndPage: 1
387 | %%Trailer
388 | %%Pages: 1
389 | %%BoundingBox: 36 36 347 292
390 | end
391 | restore
392 | %%EOF
393 |
--------------------------------------------------------------------------------
/iot.md:
--------------------------------------------------------------------------------
1 | ### 引言
2 | 你可以将这个系统当成是你的毕业设计,或者用它来控制你想控制的东西,总之你可以用它来做一个最小的物联网系统。
3 |
4 | **不过,在这里可能没有那么复杂的功能,因为强调的是最小。**
5 |
6 | BareMinimum,这也是为什么我没有改Arduino上面的工程名的原因,因为它是最小的,(PS:大家都懂的,如果玩硬件)。物联网,这个东西一直很复杂,也不是很复杂,只是从硬件到软件涉及到的东西过多了,不止一点点。当然写在本文的方案也有很多,不止这一个,只是这个算是基本的最小的,仅此而已。(转载保留 [Phodal's
7 | Blog](http://www.phodal.com/blog/bare-minimum-iot/) )
8 |
9 | 关于
10 | ----
11 |
12 | 源码:[https://github.com/gmszone/iot](https://github.com/gmszone/iot)
13 |
14 | 文档可能没有足够的详细,因为剩下的部分都可以Google到,这里就不写详细了。
15 |
16 | ### 框架:
17 |
18 | - PHP Laravel
19 | - jQuery (Javascript 主要用于Ajax)
20 | - jQuery Mobile(可选)(我觉得我有点懒,于是从原来做的项目直接拿了出来)
21 | - Bootstrap (可选) (其实没有多大实际用处,只是因为好看和jQuery Mobile一样)
22 |
23 | ### 语言:
24 |
25 | Processing/C/C++ : Arduino
26 |
27 | Python : Raspberry Pi 或者与之相近设备都可以使用,实现与 Arduino 串口通信
28 |
29 | PHP 我学得不是很好,因为 Laravel 没有让我学好,但是让我能做想做的事。
30 |
31 | ### 相关文章及专栏
32 |
33 | - CSDN - [Laravel专栏](http://blog.csdn.net/column/details/laravel.html)
34 |
35 | 1. [Laravel
36 | RESTful快速部署指南(一)](http://blog.csdn.net/phodal/article/details/15340355)
37 | 2. [Laravel
38 | RESTful快速部署指南(二)](http://blog.csdn.net/phodal/article/details/15364481)
39 | 3. [Laravel
40 | RESTful快速部署指南(三)](http://blog.csdn.net/phodal/article/details/15364481)
41 |
42 | ### 相关知识
43 |
44 | #### 软件
45 |
46 | - RESTful
47 | - Ajax
48 | - JSON
49 |
50 | #### 硬件
51 |
52 | - 硬件编程
53 | - 串口通信
54 |
55 | ### 关于服务器
56 |
57 | - Nginx 需要配置,具体配置可以参照 Github 上面的代码
58 | - LNMP 直接用上面的会比较简单,但是可能也会遇到一些问题。
59 | - Phpmyadmin 最好需要有这个,如果不是很精通 MySQL
60 |
61 | ### 补充说明
62 |
63 | Arduino 不是必需的,只要你懂得如何用你的芯片进行串口通信。
64 |
65 | 考虑到 Raspberry Pi 的成本可能会有点高,你可以试着用 OpenWRT
66 | Linux,主要用在路由器用的,上面可以跑 Python。或者等等过些时候的小米路由器,可以加这个在上面。
67 |
68 | 如果你没有服务器没有 Raspberry
69 | Pi,那就找个路由器来当服务器吧,相关文章如下 :
70 |
71 | [Openwrt python,openwrt上使用Python](http://blog.csdn.net/phodal/article/details/8521712)
72 |
73 | 对了,如果你觉得哪里有问题记得在 Github 上提出来,而不是在原文。
74 |
75 | ### 注意
76 |
77 | !请尽可能少用我的网站做测试
78 |
79 |
80 | 如何开始
81 | --------
82 |
83 | $ git clone https://github.com/gmszone/iot.git
84 | $ cp iot/rest
85 |
86 | 创建一个新的数据库,如iot 编辑 app/config/database.php
87 |
88 |
89 | 'mysql' => array(
90 | 'driver' => 'mysql',
91 | 'host' => 'localhost',
92 | 'database' => 'iot',
93 | 'username' => 'root',
94 | 'password' => ' ',
95 | 'charset' => 'utf8',
96 | 'collation' => 'utf8_unicode_ci',
97 | 'prefix' => '',
98 | ),
99 |
100 |
101 |
102 | 配置nginx,添加,详细可参考nginx下面的配置
103 |
104 |
105 | # include /etc/nginx/includes/enforce_non_www;
106 | if ($host ~* ^www\.(.*))
107 | {
108 | set $host_without_www $1;
109 | rewrite ^/(.*)$ $scheme://$host_without_www/$1 permanent;
110 | }
111 |
112 | # Check if file exists
113 | if (!-e $request_filename)
114 | {
115 | rewrite ^/(.*)$ /index.php?/$1 last;
116 | break;
117 | }
118 |
119 |
120 |
121 | 测试
122 |
123 | ```
124 | $ sudo python python/get.py
125 | ```
126 |
127 |
128 | 再根据需要修改端口,视真实的端口而修改。
129 |
130 | ##关于物联网##
131 | 物联网(Internet of Things,缩写IOT)是一个基于互联网、传统电信网等信息承载体,让所有能够被独立寻址的普通物理对象实现互联互通的网络。
132 |
133 |
134 | 物联网一般为无线网,由于每个人周围的设备可以达到一千至五千个,所以物联网可能要包含500万亿至一千万亿个物体,在物联网上,每个人都可以应用电子标签将真实的物体上网联结,在物联网上都可以查找出它们的具体位置。通过物联网可以用中心计算机对机器、设备、人员进行集中管理、控制,也可以对家庭设备、汽车进行遥控,以及搜寻位置、防止物品被盗等各种应用。
135 |
136 | 简单的来说 Internet 是一个由计算机组成的网络,那么物联网就是一个由物体(Things)组成的网络,只不过其依赖于 Internet,是 Internet 的一部分。
137 |
138 | ##最小物联网系统##
139 | 这个也就是我们要讨论的主题了,我们要做的最小物联网系统其实也就相当于是一个平台。我们可以上传我们各种物体的信息,同时给予这些物体一些属性,我们也可以通过网络来控制这些物体,而他们之间也可以相互控制。因此,我们需要给他们提供一个网络,这就是RESTful的由来。
140 |
141 | 所以我们也稍微了解一下RESTful吧。
142 |
143 | ###RESTful###
144 |
145 | REST 从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表征。获得这些表征致使这些应用程序转变了其状态。随着不断获取资源的表征,客户端应用不断地在转变着其状态,所谓表征状态转移(Representational State Transfer)。
146 |
147 | 我们的世界是由资源来组成的,一个物体也就相当于是一个资源,以这种方式来构建我们的物联网系统,在目前来说是再好不过的一个方案了。
148 |
149 | REST架构就是希望能够统一这一类的Hypermedia Controls, 赋予他们标准的, 高度可扩展的标准语义及表现形式, 使得甚至无人工干预的机器与机器间的通用交互协议边的可能.
150 |
151 | 这个也就是我们的目的了,物联网最后的核心就是使物体与物体之间的交互成为可能。
152 |
153 | 那么,这里也就解释了为什么我们要用RESTful来做这个最小系统的原因了。
154 |
155 | ###最小系统中的RESTful###
156 |
157 | 例如,一个简单的例子,
158 | 列举所有物体状态,
159 |
160 | $ GET http://localhost/athome
161 |
162 | 呈现某一特定状态,
163 |
164 | $ GET http://localhost/athome/1/
165 |
166 | 剩下的部分这里就不多说了,多说无益,可以自己谷歌去。
167 |
168 | 接着我们要讨论的就是系统框架
169 |
170 | ##系统框架##
171 |
172 | [image]: ./struct.bmp "系统框架"
173 | ![系统框架][image]
174 |
175 | ###为什么是 Raspberry Pi###
176 |
177 | Raspberry Pi 在这里只是充当了数据的发送和接收,虽然我们可以直接将 Raspberry Pi 作为控制的对象,但是将这个从中剥离来讲清楚系统的结构会更加简单。从而,可以让我们把核心注意力聚焦在要解决的问题上,也就是数据传送,每个部分都可以简单地从系统剥离出来,用另外的事物来替换。
178 |
179 |
180 | ###为什么是 Arduino###
181 |
182 | 这个问题的答案和上面是一样的,只是因为有些搞物联网是从软件过来的,对于他们来说去理解端口的难道可能有点大。所以,我们在简化系统设计的同时,也把系统的代码简化了。因为 Arduino 足够的简单,我们可以关心问题的本质,而不是如何去编程。
183 |
184 | ###为什么是Ajax###
185 |
186 | AJAX即 "Asynchronous JavaScript and XML" (异步的 JavaScript 与 XML 技术),指的是一套综合了多项技术的浏览器端网页开发技术。
187 |
188 |
189 | 这里的目的只是在于演示如何运用这些数据,使它具有他应有的价值,而不在于技术本身。当然 ajax 不是必需的,如果你需要的只是用来控制这个灯。
190 |
191 | ###为什么是 Laravel###
192 | 只是因为个人喜爱,你也可以用 Ruby On Rails 来搭建这样一个功能,或者是 Java。只不过 PHP 在我的服务器上运行得挺不错的,而且我又不需要重新去写配置那些配置。
193 | 同时 Laravel 可以简单的开发我们所需要的功能,换句话说他是 PHP 世界的 Ruby On Rails。
194 |
195 |
196 | 这里不会再重述之前的问题,这里只是将需要的步骤一个个写下来,然后丢到这里好好说一下。至于 RESTful 是什么,前面已经介绍了,就不再重复了。那么下面,我们就用 Laravel 来搭建一个平台给物联网用的。
197 |
198 | ##安装 Laravel##
199 | 这个就比较简单了,不过在那之前你要有 gi t以及安装了 php 环境,这个在 linux 上面比较好实现,可以用 Raspberry Pi 或者是你的电脑来做这个,不一定用用上你的服务器。
200 |
201 | $ git clone https://github.com/laravel/laravel
202 |
203 | 先 clone 这个 git,如果你没有安装好 PHP,请安装好,and go on。
204 |
205 | $ cd laravel
206 |
207 | laravel 用到了 php 的包管理工具 composer,于是我们还需要用到 composer,与 Laravel 相比也算是一个优雅的工具。
208 |
209 | $ curl -sS https://getcomposer.org/installer | php
210 |
211 | 这里推荐的是 linux 系统,如果你是 *nix 都是可以的(ps:mac os x属于unix分支),除了 windows,所以如果是 windows,请直接下载
212 |
213 | [Composer-Setup][composer]
214 |
215 | 然后让我们安装所需要的那些包
216 |
217 | $ php composer.phar install
218 |
219 | 当然这里用的是比较通用的,如果你是 *nix,有支持可以直接
220 |
221 | $ composer install
222 |
223 |
224 | ##配置MySQL##
225 | 这里并不会列举 MySQL 的安装方法,如果你是 openSUSE,可以
226 |
227 | $ zypper install mysql
228 |
229 | 这个也可以,不过最近我尽量到迁移到 MariaDB 了。
230 |
231 | $ zypper install mariadb
232 |
233 | 当然,最简单的方法是直接上官网。这里说的是修改 database.php
234 |
235 | app/config/database.php
236 |
237 | 要修改的就是这个
238 |
239 | 'mysql' => array(
240 | 'driver' => 'mysql',
241 | 'host' => 'localhost',
242 | 'database' => 'iot',
243 | 'username' => 'root',
244 | 'password' => '940217',
245 | 'charset' => 'utf8',
246 | 'collation' => 'utf8_unicode_ci',
247 | 'prefix' => '',
248 | ),
249 |
250 | 如果你已经有phpmyadmin,似乎对你来说已经很简单了,如果没有的话,就直接用
251 |
252 | $ mysql -uroot -p
253 |
254 | 来创建一个新的
255 |
256 | CREATE DATABASE IF NOT EXISTS iot default charset utf8 COLLATE utf8_general_ci;
257 |
258 | [composer]: https://getcomposer.org/Composer-Setup.exe
259 |
260 |
261 | 数据库的目的在于存储数据等等的闲话这里就不多说了,创建一个RESTful的目的在于产生下面的JSON格式数据,以便于我们在Android、Java、Python、jQuery等语言框架或者平台上可以调用,最主要的是可以直接用Ajax来产生更炫目的效果。
262 |
263 | {
264 | id: 1,
265 | temperature: 14,
266 | sensors1: 12,
267 | sensors2: 12,
268 | led1: 0
269 | }
270 |
271 | ##数据库迁移##
272 |
273 | 这个名字是源自于Ruby On Rails在那时候的印象,不直接使用MySQL的目的在于让我们可以专注于过程。
274 |
275 | ###创建表###
276 | 表的概念,类似于在Excel中的表,如果你真实不懂数据库。
277 | 让我们创建一个athomes的表,为什么是athomes,因为以前在写android程序的时候就叫的是athome,忽略掉这些次要的因素吧。
278 |
279 | $ php artisan migrate:make create_athomes_table
280 |
281 | 打开 app/database/migrations/***create_athomes_table.php这里的***是由日期和某些东西组成的,修改生成的代码为下面。
282 |
283 | use Illuminate\Database\Schema\Blueprint;
284 | use Illuminate\Database\Migrations\Migration;
285 |
286 | class CreateAthomesTable extends Migration {
287 |
288 | public function up()
289 | {
290 | Schema::create('athomes', function(Blueprint $table)
291 | {
292 | $table--->increments('id');
293 | $table->float('temperature');
294 | $table->float('sensors1');
295 | $table->float('sensors2');
296 | $table->boolean('led1');
297 | $table->timestamps();
298 | });
299 | }
300 |
301 | public function down()
302 | {
303 | Schema::drop('athomes');
304 | }
305 |
306 | }
307 |
308 | 意思大致就是id是自加的,也就是我们在localhost/athome/{id},当我们创建一个新的数据的时候,会自动加上去,最后一个timestamps批的是时间,会包含创建时间和修改时间。
309 | 剩下的temperature,sensors1,sensors2是小数,以及只有真和假的led1。
310 |
311 | ###数据库迁移###
312 | 我们只是写了我们需要的数据的格式而并没有丢到数据库里,
313 |
314 | $ php artisan migrate
315 |
316 | 这个就是我们执行迁移的命令,如果你用phpmyadmin可以直接打开查看,没有的话,可以。
317 |
318 | $ mysql -uroot -p
319 |
320 | use iot;
321 | select * from athomes;
322 |
323 | 就可以看到我们写的东西,那么接下来就是创建RESTful 服务了
324 |
325 |
326 | ##创建RESTful##
327 |
328 | 用下面的代码实现我们称之为Athomes控制器的创建
329 |
330 | $ php artisan controller:make AthomesController
331 |
332 | 就会在app/controllers下面生成下面的代码
333 |
334 | class AthomesController extends \BaseController {
335 |
336 | /**
337 | * Display a listing of the resource.
338 | *
339 | * @return Response
340 | */
341 | public function index()
342 | {
343 | //
344 | }
345 |
346 | /**
347 | * Show the form for creating a new resource.
348 | *
349 | * @return Response
350 | */
351 | public function create()
352 | {
353 | //
354 | }
355 |
356 | /**
357 | * Store a newly created resource in storage.
358 | *
359 | * @return Response
360 | */
361 | public function store()
362 | {
363 | //
364 | }
365 |
366 | /**
367 | * Display the specified resource.
368 | *
369 | * @param int $id
370 | * @return Response
371 | */
372 | public function show($id)
373 | {
374 | //
375 | }
376 |
377 | /**
378 | * Show the form for editing the specified resource.
379 | *
380 | * @param int $id
381 | * @return Response
382 | */
383 | public function edit($id)
384 | {
385 | //
386 | }
387 |
388 | /**
389 | * Update the specified resource in storage.
390 | *
391 | * @param int $id
392 | * @return Response
393 | */
394 | public function update($id)
395 | {
396 | //
397 | }
398 |
399 | /**
400 | * Remove the specified resource from storage.
401 | *
402 | * @param int $id
403 | * @return Response
404 | */
405 | public function destroy($id)
406 | {
407 | //
408 | }
409 |
410 | }
411 |
412 | ###Laravel Resources###
413 |
414 | 上面的代码过于沉重,请让我用 Ctrl+C 来带来点知识吧。
415 |
416 |
417 | 所以我们只需要专注于创建 create, edit, show, destory 等等。好吧,你可能没有耐心了,但是在修改这个之前我们需要先在
418 | app/model 加个 class
419 |
420 | class Athomes extends Eloquent {
421 | protected $table = 'athomes';
422 | }
423 |
424 | 如果你想要的只是控制器Athomes的代码的话。。
425 |
426 |
427 | class AthomesController extends \BaseController {
428 |
429 | /**
430 | * Display a listing of the resource.
431 | *
432 | * @return Response
433 | */
434 | public $restful=true;
435 |
436 | protected $athome;
437 |
438 | public function __construct(Athomes $athome)
439 | {
440 | $this--->athome = $athome ;
441 | }
442 |
443 | public function index()
444 | {
445 | $maxid=Athomes::all();
446 | return Response::json($maxid);
447 | }
448 |
449 | /**
450 | * Show the form for creating a new resource.
451 | *
452 | * @return Response
453 | */
454 | public function create()
455 | {
456 | $maxid=Athomes::max('id');
457 | return View::make('athome.create')->with('maxid',$maxid);
458 | }
459 |
460 | /**
461 | * Store a newly created resource in storage.
462 | *
463 | * @return Response
464 | */
465 | public function store()
466 | {
467 | // validate
468 | // read more on validation at http://laravel.com/docs/validation
469 | $rules = array(
470 | 'led1'=>'required',
471 | 'sensors1' => 'required|numeric|Min:-50|Max:80',
472 | 'sensors2' => 'required|numeric|Min:-50|Max:80',
473 | 'temperature' => 'required|numeric|Min:-50|Max:80'
474 | );
475 | $validator = Validator::make(Input::all(), $rules);
476 |
477 | // process the login
478 | if ($validator->fails()) {
479 | return Redirect::to('athome/create')
480 | ->withErrors($validator)
481 | ->withInput(Input::except('password'));
482 | } else {
483 | // store
484 | $nerd = new Athomes;
485 | $nerd->sensors1 = Input::get('sensors1');
486 | $nerd->sensors2 = Input::get('sensors2');
487 | $nerd->temperature = Input::get('temperature');
488 | $nerd->led1 = Input::get('led1');
489 | $nerd->save();
490 |
491 | // redirect
492 | Session::flash('message', 'Successfully created athome!');
493 | return Redirect::to('athome');
494 | }
495 | }
496 |
497 | /**
498 | * Display the specified resource.
499 | *
500 | * @param int $id
501 | * @return Response
502 | */
503 | public function show($id)
504 | {
505 | $myid=Athomes::find($id);
506 | $maxid=Athomes::where('id','=',$id)
507 | ->select('id','temperature','sensors1','sensors2','led1')
508 | ->get();
509 | return Response::json($maxid);
510 | }
511 |
512 | /**
513 | * Show the form for editing the specified resource.
514 | *
515 | * @param int $id
516 | * @return Response
517 | */
518 | public function edit($id)
519 | {
520 | // get the nerd
521 | $athome = Athomes::find($id);
522 |
523 | // show the edit form and pass the nerd
524 | return View::make('athome.edit')
525 | ->with('athome', $athome);
526 | }
527 |
528 | /**
529 | * Update the specified resource in storage.
530 | *
531 | * @param int $id
532 | * @return Response
533 | */
534 | public function update($id)
535 | {
536 | // validate
537 | // read more on validation at http://laravel.com/docs/validation
538 | $rules = array(
539 | 'led1'=>'required|',
540 | 'sensors1' => 'required|numeric|Min:-50|Max:80',
541 | 'sensors2' => 'required|numeric|Min:-50|Max:80',
542 | 'temperature' => 'required|numeric|Min:-50|Max:80'
543 | );
544 | $validator = Validator::make(Input::all(), $rules);
545 |
546 | // process the login
547 | if ($validator->fails()) {
548 | return Redirect::to('athome/' . $id . '/edit')
549 | ->withErrors($validator);
550 | } else {
551 | // store
552 | $nerd = Athomes::find($id);
553 | $nerd->sensors1 = Input::get('sensors1');
554 | $nerd->sensors2 = Input::get('sensors2');
555 | $nerd->temperature = Input::get('temperature');
556 | $nerd->led1 = Input::get('led1');
557 | $nerd->save();
558 |
559 | // redirect
560 | Session::flash('message', 'Successfully created athome!');
561 | return Redirect::to('athome');
562 | }
563 | }
564 |
565 | /**
566 | * Remove the specified resource from storage.
567 | *
568 | * @param int $id
569 | * @return Response
570 | */
571 | public function destroy($id)
572 | {
573 | // delete
574 | $athome = Athomes::find($id);
575 | $athome->delete();
576 | if(is_null($athome))
577 | {
578 | return Response::json('Todo not found', 404);
579 | }
580 | // redirect
581 | Session::flash('message', 'Successfully deleted the nerd!');
582 | return Redirect::to('athome');
583 | }
584 |
585 | }
586 |
587 | 希望你能读懂,没有的话,关注下一节。
588 |
589 | 下面这部分来自于之前的博客,这里就不多加论述了。
590 | 这个也就是我们要的模板,
591 |
592 | 修改 Create()
593 | ------------
594 |
595 |
596 | public function create()
597 | {
598 | $maxid=Athomes::max('id');
599 | return View::make('athome.create')->with('maxid',$maxid);
600 | }
601 |
602 |
603 |
604 | 这里需要在app/views/创建一个athome里面创建一个create.blade.php,至于maxid,暂时还不需要,后面会用到show。如果只需要模板,可以简化为
605 |
606 |
607 | public function create()
608 | {
609 | return View::make('athome.create');
610 | }
611 |
612 |
613 | 这里只是对其中代码的进行一下说明。
614 |
615 | 创建表单
616 | --------
617 |
618 | ### 创建表单之前
619 |
620 | 由于使用到了bootstrap以及bootstrap-select,记得添加css。
621 |
622 |
623 |
624 |
625 | 以及javascript
626 |
627 |
628 |
629 |
630 |
633 |
634 |
635 | ### 创建表单
636 |
637 | 这里用到的是之前提到的那个作者写下的,稍微修改了一下。
638 |
639 |
640 | {{ HTML::ul($errors->all()) }}
641 | {{ Form::open(array('url' => 'athome')) }}
642 |
643 |
644 | {{ Form::label('led1', '开关1') }}
645 | {{ Form::select('led1',array('关','开'),$selected=NULL,array('class'=>'selectpicker')) }}
646 |
647 |
648 |
649 |
650 | {{ Form::label('sensors1', 'sensors1') }}
651 | {{ Form::text('sensors1', Input::old('sensors1'), array('class' => 'form-control')) }}
652 |
653 |
654 |
655 | {{ Form::label('sensors2', 'sensors2') }}
656 | {{ Form::text('sensors2', Input::old('sensors2'), array('class' => 'form-control')) }}
657 |
658 |
659 |
660 | {{ Form::label('temperature', 'temperature') }}
661 | {{ Form::text('temperature', Input::old('temperature'), array('class' => 'form-control')) }}
662 |
663 |
664 | {{ Form::submit('Create!', array('class' => 'btn btn-primary')) }}
665 |
666 | {{ Form::close() }}
667 |
668 |
669 |
670 | 开关一开始打算用 checkbox,加上 bootstrap-switch 实现
671 | ON OFF
672 | 弱弱地觉得还是没掌握好的节奏,所以最后用 select 来实现。
673 |
674 | 还需要修改一下之前的 create(),添加一行
675 |
676 | return Redirect::to('athome');
677 |
678 | 也就是添加完后,重定向到首页查看,最后例子给出的 create 如下
679 |
680 | public function store()
681 | {
682 | $rules = array(
683 | 'led1'=>'required',
684 | 'sensors1' => 'required|numeric|Min:-50|Max:80',
685 | 'sensors2' => 'required|numeric|Min:-50|Max:80',
686 | 'temperature' => 'required|numeric|Min:-50|Max:80'
687 | );
688 | $validator = Validator::make(Input::all(), $rules);
689 |
690 | if ($validator->fails()) {
691 | return Redirect::to('athome/create')
692 | ->withErrors($validator);
693 | } else {
694 | // store
695 | $nerd = new Athomes;
696 | $nerd->sensors1 = Input::get('sensors1');
697 | $nerd->sensors2 = Input::get('sensors2');
698 | $nerd->temperature = Input::get('temperature');
699 | $nerd->led1 = Input::get('led1');
700 | $nerd->save();
701 |
702 | Session::flash('message', 'Successfully created athome!');
703 | return Redirect::to('athome');
704 | }
705 | }
706 |
707 | 编辑 edit
708 | --------
709 |
710 | 完整的 blade 模板文件
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 | @yield('title')
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 | Edit {{ $athome->id }}
733 |
734 |
735 | {{ HTML::ul($errors->all()) }}
736 |
737 | {{ Form::model($athome, array('route' => array('athome.update', $athome->id), 'method' => 'PUT')) }}
738 |
739 |
740 | {{ Form::label('led1', '开关1') }}
741 | {{ Form::select('led1',array('关','开'),$selected=NULL,array('class'=>'selectpicker')) }}
742 |
743 |
744 |
745 |
746 | {{ Form::label('sensors1', '传感器1') }}
747 | {{ Form::text('sensors1', Input::old('sensors1'), array('class' => 'form-control')) }}
748 |
749 |
750 |
751 | {{ Form::label('sensors2', '传感器2') }}
752 | {{ Form::text('sensors2', Input::old('sensors2'), array('class' => 'form-control')) }}
753 |
754 |
755 |
756 | {{ Form::label('temperature', '温度传感器') }}
757 | {{ Form::text('temperature', Input::old('temperature'), array('class' => 'form-control')) }}
758 |
759 |
760 |
761 | {{ Form::submit('Edit the Nerd!', array('class' => 'btn btn-primary')) }}
762 |
763 | {{ Form::close() }}
764 |
765 |
766 |
767 |
768 |
769 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 | 最后效果见:[http://b.phodal.com/][bphodal]
789 |
790 | 代码位置:[http://b.phodal.com/js/app.js][appjs]
791 |
792 | 我觉得似乎我把这个代码写长了,但是我不是故意,只是必需的。先观察 Ajax 部分:
793 |
794 | ##Ajax##
795 |
796 | 剥离后的Ajax部分代码如下所示,主要用的是 jQuery 框架的 getJSON 来实现的
797 |
798 | var dataLength = [];
799 |
800 | function drawTemp() {
801 | var zero = [];
802 | $.getJSON('/athome/', function(json) {
803 | var items = [];
804 | dataLength.push(json.length);
805 | $.each(json, function(key, val) {
806 | zero.push(val.temperature);
807 | });
808 | };
809 |
810 | 实际上,我们做的只是从 /athome/ 下面获取数据,再将数据堆到数组里面,再把这部分放到图形中。等等,什么是 Ajax?
811 |
812 | - AJAX : Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
813 | - AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
814 | - AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。
815 |
816 | JSON我们前面也已经了解过了,看看getJSON吧。
817 |
818 | ####jQuery. getJSON####
819 | 方法定义:jQuery.getJSON( url, data, callback )
820 |
821 | 通过get请求得到json数据
822 |
823 | - ·url 用于提供 json 数据的地址页
824 | - ·data(Optional) 用于传送到服务器的键值对
825 | - ·callback(Optional) 回调函数,json 数据请求成功后的处理函数
826 |
827 | 我想你似乎应该懂得了一点,就是在不刷新网页的同时,用 javascript 获取数据放到图表上,就这么简单。
828 |
829 | ##HighChart##
830 | 再省去一部分,摘自我原来的博客
831 |
832 | HIGHCHARTS
833 | Highcharts 是一个制作图表的纯 Javascript 类库,主要特性如下:
834 |
835 | - 兼容性:兼容当今所有的浏览器,包括 iPhone、IE 和火狐等等;
836 | - 对个人用户完全免费;
837 | - 纯 JS,无 BS;
838 | - 支持大部分的图表类型:直线图,曲线图、区域图、区域曲线图、柱状图、饼装图、散布图;
839 | - 跨语言:不管是 PHP、Asp.net 还是 Java 都可以使用,它只需要三个文件:一个是Highcharts 的核心文件 highcharts.js,还有 a canvas emulator for IE 和 Jquery类库或者 MooTools 类库;
840 | - 提示功能:鼠标移动到图表的某一点上有提示信息;
841 | - 放大功能:选中图表部分放大,近距离观察图表;
842 | - 易用性:无需要特殊的开发技能,只需要设置一下选项就可以制作适合自己的图表;
843 | - 时间轴:可以精确到毫秒;
844 |
845 | 不过因为项目原因,所以可能不会再使用这个,只对个人免费,现在的考虑是基于D3做一个新的。
846 |
847 | ###官方示例代码###
848 |
849 | $(function () {
850 | $('#container').highcharts({
851 | title: {
852 | text: 'Monthly Average Temperature',
853 | x: -20 //center
854 | },
855 | subtitle: {
856 | text: 'Source: WorldClimate.com',
857 | x: -20
858 | },
859 | xAxis: {
860 | categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
861 | 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
862 | },
863 | yAxis: {
864 | title: {
865 | text: 'Temperature (°C)'
866 | },
867 | plotLines: [{
868 | value: 0,
869 | width: 1,
870 | color: '#808080'
871 | }]
872 | },
873 | tooltip: {
874 | valueSuffix: '°C'
875 | },
876 | legend: {
877 | layout: 'vertical',
878 | align: 'right',
879 | verticalAlign: 'middle',
880 | borderWidth: 0
881 | },
882 | series: [{
883 | name: 'Tokyo',
884 | data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
885 | }, {
886 | name: 'New York',
887 | data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
888 | }, {
889 | name: 'Berlin',
890 | data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
891 | }, {
892 | name: 'London',
893 | data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
894 | }]
895 | });
896 | });
897 |
898 | 我承认我也不想看这些代码,但是这样子似乎使原文的长度变长了。大部分人也省得去查找了。
899 |
900 | 所以我们要做的只是用数组代替data
901 |
902 | ##jQuery Mobile##
903 |
904 | 在首页上看到的那个效果是 jQuery Mobile。。
905 |
906 |
907 | [bphodal]:http://b.phodal.com/
908 | [appjs]:http://b.phodal.com/js/app.js
909 |
910 |
911 | 这里写的数据通讯指的是两部分,一部分是与服务器,一部分是与单片机。这样设计的另外一个原因是,更好的分层,能让我们更好的理解这个系统。负责这个功能的这里用的是 Raspberry Pi,或者是你的PC两者都可以,我想你也看到了之前的代码。那么先让我们看看与服务器通信的这部分。
912 |
913 | ##服务器通讯##
914 | 示例中的代码是这样子的,如果你没有看懂的话,那么等等 。
915 |
916 | import json,urllib2
917 |
918 | url="http://b.phodal.com/athome/1"
919 | while True:
920 | status=json.load(urllib2.urlopen(url))[0]['led1']
921 |
922 | ###GET###
923 |
924 | 看看get.py的代码,这个是没有压缩的,换句话说,会比较好理解一点
925 |
926 | import json
927 | import urllib2
928 |
929 | url="http://b.phodal.com/athome/1"
930 |
931 | while 1:
932 | date=urllib2.urlopen(url)
933 | result=json.load(date)
934 | status=result[0]['led1']
935 | print status
936 |
937 | 这里做的事情有两件,一件是从服务器 GET,另外一个就是解析 JSON 数据。
938 |
939 | 如果你用的是 *nix,应该就自带 curl 了,可以试着用下面的命令来 GET
940 |
941 | $ curl http://b.phodal.com/athome/1
942 |
943 | 那么应该返回的是下面的结果
944 |
945 | [{"id":1,"temperature":14,"sensors1":12,"sensors2":12,"led1":0}]
946 |
947 | 用在python里面就是
948 |
949 | urllib2.open("http://b.phodal.com/athome/1")
950 |
951 |
952 | ###数据解析###
953 | python 带有 json 解析模块,我们在这里只需要用 json.load() 来解析获取下面的 date 就可以了
954 |
955 | result=json.load(date)
956 |
957 | 解析完的 result 相当于是C语言里面的数组,在这里相当于是一个二维数组,我们只需要 result[0]['led1'],在 python 里面叫做字典,意思就是和字典一样。
958 |
959 | "led1":0
960 |
961 | led1的值是 0,所以 result[0]['led1]的值是 0,如果你用过 Ruby,那么这个和其中的 Hash 差不多。
962 |
963 | 因此在这里我们拿到了服务器上面的控制状态的指令,也就是 0。我们还需要传给单片机,也就是 Arduino。。
964 |
965 | 在我们完成了前面的几部分之后,我们也需要把这最后一部分解决,这里更多的是硬件, Arduino 的存在可以让硬件更简单。
966 |
967 | ##Arduino##
968 |
969 | Arduino 是一款便捷灵活、方便上手的开源电子原型平台,包含硬件(各种型号的arduino板)和软件(arduino IDE)。它适用于艺术家、设计师、爱好者和对于“互动”有兴趣的朋友们。
970 |
971 | 那么让我们先来看看我们写的代码。
972 |
973 | void setup() {
974 | Serial.begin(9600);
975 | pinMode(13,OUTPUT);
976 | }
977 |
978 | int serialData;
979 | void loop() {
980 | String inString = "";
981 | while (Serial.available()> 0)
982 | {
983 | int inChar = Serial.read();
984 | if (isDigit(inChar)) {
985 | inString += (char)inChar;
986 | }
987 | serialData=inString.toInt();
988 | Serial.print(serialData);
989 | }
990 | if(serialData==1){
991 | digitalWrite(13,HIGH);
992 | }else{
993 | digitalWrite(13,LOW);
994 | }
995 | }
996 |
997 | 这个代码看上去似乎会有点复杂,但是让我们看点基础的,也就是由 Arduino 来控制一个 LED 的亮和灭。
998 |
999 | int led = 13;
1000 |
1001 | void setup() {
1002 | pinMode(led, OUTPUT);
1003 | }
1004 |
1005 | void loop() {
1006 | digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
1007 | delay(1000); // wait for a second
1008 | digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
1009 | delay(1000); // wait for a second
1010 | }
1011 |
1012 | 这个也就是来自于官方的示例程序,而我们要做的东西也和这个差不多,只是这个是自动的,上面那个是由串口通信来实现的。
1013 |
1014 | ##串口通信##
1015 |
1016 | 串行接口是一种可以将接受来自 CPU 的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给 CPU 的器件。一般完成这种功能的电路,我们称为串行接口电路。
1017 |
1018 | 简单地来说,我们誻就是用这个来实现通信的,用之前的 Raspberry Pi 发送 1 和 0 给 Arduino。那么我们在 Arduino 上就只是接受和执行,这个由 loop 里面的 if 来执行
1019 |
1020 | ###初始化串口###
1021 |
1022 | 如果你真心不喜欢51上的复杂的串口,那么我想 Arduino 又是解放双手的东西了。
1023 |
1024 | Serial.begin(9600);
1025 |
1026 | 这个就是串口初始化,速率为 9600。
1027 |
1028 | ###串口读取###
1029 |
1030 |
1031 | while (Serial.available()<0)
1032 | {
1033 | int inChar = Serial.read();
1034 | if (isDigit(inChar)) {
1035 | inString += (char)inChar;
1036 | }
1037 | serialData=inString.toInt();
1038 |
1039 | 用于读取的就是这么一行
1040 |
1041 | int inChar=Serial.read()
1042 |
1043 | 而下面的部分则是刚我们接收到的数据转换为1,由于接到的为 char 类型,那么我们需要转为转为 int 进行判断。
1044 |
1045 | ####为什么不直接用'1'####
1046 |
1047 | 只是为了写给需要的同学用的,也可以直接在上面用 if(serialData=='1'),上面写可以让后期扩展的时候方便一点。
1048 |
1049 | 加上之前的部分,我们算是把开源的地方做了一个遍,因为 Windows Phone 需要在 Windows 8 上开发的原因,加上我没有 Macbook 以及 iPhone,所以在这里只会有一个 Android 的示例。当然,原因上也是一样的,相信这些也不会很难。
1050 |
1051 | 原理上和 Raspberry Pi 的原理很像,也就是GET数据,然后解析,也和服务端差不多。当然在最开始的代码里有拨打电话、发短信等等功能,只是我们似着简化系统为我们想要的理想化模型。
1052 |
1053 | 源码地址[Home-Anywhere][3]
1054 | ##Android开发##
1055 |
1056 | 写在这里的原因是,因为我也不太擅长,所以也给不了多少指导。只是我试着去写过这样一个程序,有了几个版本,所以算是知道怎样去开发,但是相比较于专业于我的人还是有很多不足,所以希望懂得的人给些建议和意见。
1057 |
1058 | ###浅析###
1059 | 我们需要的库和在 Raspberry Pi 上的类似,如果你不需要的话,可以看看之前的文章:
1060 |
1061 | [最小物联网系统(七)——与服务器通讯][comm]
1062 |
1063 | 因为CSDN上发这些文章已经没有足够的必要,在之前的部分文章实在上是针对这部分写的, 只是在自己的博客上梳理了一遍。
1064 |
1065 | 我们还要做的事情就是有一个 RESTful 的库,以及解析 JSON 用的。
1066 |
1067 | 于是就有了下面两个
1068 |
1069 | ####RESTclient####
1070 | 这个类的原文在[calling-web-services-in-android-using-httpclient][2],专门用于 REST 用的,如果熟悉的人我想一看就知道了。
1071 |
1072 | ####GSON####
1073 | 这个库来自于 Google,一个不错的库。
1074 |
1075 | 所以我们就构成了开发所需的两部分基础。
1076 |
1077 | ##Android##
1078 | 关于 Android 开发环境的配置这个网上有,最简单的办法是直接下载一个 Android Studio。
1079 |
1080 | 下面只是列举一些代码以及可能会遇到的问题。
1081 |
1082 | ###Android 4.0 Web问题###
1083 |
1084 | 如在源码里看到的那样,
1085 |
1086 | StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
1087 | .detectDiskReads()
1088 | .detectDiskWrites()
1089 | .detectNetwork() // or .detectAll() for all detectable problems
1090 | .penaltyLog()
1091 | .build());
1092 | StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
1093 | .detectLeakedSqlLiteObjects()
1094 | .detectLeakedClosableObjects()
1095 | .penaltyLog()
1096 | .penaltyDeath()
1097 | .build());
1098 |
1099 | 这部分用于Android 4.0的网络,2.*可以不需要。
1100 |
1101 | ###JSONObject 以及 JSONArray###
1102 |
1103 | 会产生下面这些代码的原因是下载下来的JSON数据是类似于二维数组,所以需要转换,下面的代码有些丑陋,但是可能工作得很好。
1104 |
1105 | JSONArray jArray = new JSONArray(client.getResponse());
1106 | JSONObject jObj=jArray.getJSONObject(0);
1107 |
1108 | ###handlerData 的由来###
1109 |
1110 | public GsonBuilder gsonb = new GsonBuilder();
1111 | public Gson gson = gsonb.create();
1112 | typePhoData phoData;
1113 |
1114 | public handlerData(JSONObject jObj){
1115 | phoData = gson.fromJson(jObj.toString(),
1116 | typePhoData.class);
1117 | }
1118 | public int get_id(){
1119 | return phoData.id;
1120 | }
1121 |
1122 | public double get_sensors1(){
1123 | return phoData.sensors1;
1124 | }
1125 |
1126 | public double get_sensors2(){
1127 | return phoData.sensors2;
1128 | }
1129 |
1130 | public double get_temperature(){
1131 | return phoData.temperature;
1132 | }
1133 |
1134 | public int get_led1(){
1135 | return phoData.led1;
1136 | }
1137 |
1138 | public class typePhoData{
1139 | public int led1;
1140 | public double temperature;
1141 | public double sensors1;
1142 | public double sensors2;
1143 | public int id;
1144 | }
1145 |
1146 | 在某些程度上,我好像将这些代码给复杂化了,直接放在原文里可能会好一点,不过造成这种错觉的主要原因可能是受 Java 语言的影响,不过从软件工程的某些角度上来说,这样应该会好一点。
1147 | 其他的:
1148 |
1149 | - typePhoData 的命名可能有些不尽人意,但是暂时没有想到一个合适的
1150 | - 用过几天 Ruby 后,似乎这个不算是一个问题
1151 | - 如果你要修改的话,相信这个接口也不难,也许比原来的简单,前提是你看过原来的代码。
1152 |
1153 | 整理完闭。
1154 |
1155 | ###REST POST###
1156 |
1157 | 如果你需要 POST,又懒得去看原文,那么 POST 代码在下面,只是因为我暂时没有时间去研究 Android 里面的这些,以及怎样继续这个项目,因为最小的话,似乎已经不再需要添加任何东西了。
1158 |
1159 |
1160 | RestClient clientPost = new RestClient(url);
1161 | clientPost.AddParam("temperature", "23.1");
1162 | clientPost.AddParam("led", "true");
1163 | clientPost.AddParam("title", "from android");
1164 | clientPost.AddParam("more", "nEW tESET");
1165 | try {
1166 | clientPost.Execute(RequestMethod.POST);
1167 | if(client.getResponseCode()!=200){
1168 | vshow.setText(clientPost.getErrorMessage());
1169 | }
1170 | String response2 = clientPost.getResponse();
1171 | vshow.setText(response2.toString());
1172 | } catch (Exception e) {
1173 | vshow.setText(e.toString());
1174 | }
1175 |
1176 | 大致上是类似的,注意一下都是字符就行了。
1177 |
1178 | [comm]:http://www.phodal.com/blog/bare-minimum-iot-system-date-commucation/
1179 | [2]:http://lukencode.com/2010/04/27/calling-web-services-in-android-using-httpclient/
1180 | [3]:http://github.com/gmszone/Home-Anywhere
1181 |
--------------------------------------------------------------------------------