Arduino、Web 到 IoT
http://openhome.cc 1
內容
• IoT 與 Arduino
• Arduino 與 Web 伺服器
• 硬體上的網路支援
• 雲端 IoT 服務
2
IoT 與 Arduino
• IoT
• Internet of Things
• 物聯網
程式
硬體
資料
網路
3
硬體裝置
通訊協定
資料倉儲
商務邏輯
IoT 組成
4
硬體裝置
資料的收集、產生
5
6
通訊協定
http://electronicdesign.com/iot/understanding-protocols-behind-internet-things 7
資料倉儲
資料儲存、分析工具與系統
8
9
商務邏輯
Domain knowledge? 10
Arduino
最初是針對不會寫程式,也不懂電子學,沒有任何技術背景的學生而設計,他們是
義大利北部伊夫雷亞(Ivrea)互動設計學院(Interaction Design Institute Ivrea)
的學生,身為Arduino計劃共同開發者之一的Massimo Banzi,曾在〈超越兆赫的
人們〉中提到「我們給了這些學生2到4星期的時間,讓他們製作物理運算的物品,
當時,市售的工具幾乎都是以工程師為對象,所以不管是配件或是跳線、接頭的數
量都很多。這對學生來說,似乎太過複雜,使得學生不知道該如何處置。」為了解
決這些問題,於2005年誕生的就是Arduino!
11
12
CO2 感應模組
LCD 顯示模組
原型擴充板
Arduino
溫濕度感應模組
13
14
http://www.arduino.cc/en/Main/Products 16
Arduino 與 Web 伺服器
從 S4A 開始 17
18
Web 伺服器
19
20
Firmware
USB
21
Firmware
USB
瀏覽器
代理程式
22
瀏覽器
網路
23
node-webduino
https://github.com/coopermaa/node-webduino
HTML、JavaScript、CSS
24
〈Interfacing with Other Software〉 25
Arduino and Python >>> import serial
>>> ser = serial.Serial('/dev/tty.usbserial', 9600)
>>> while True:
... print ser.readline()
'1 Hello world!\r\n'
'2 Hello world!\r\n'
'3 Hello world!\r\n'
>>> import serial # if you have not already done so
>>> ser = serial.Serial('/dev/tty.usbserial', 9600)
>>> ser.write('5')
http://playground.arduino.cc/interfacing/python 26
http://playground.arduino.cc/Interfacing/SerialNet 27
硬體上的網路支援
28
Arduino Ethernet Shield
https://www.arduino.cc/en/Main/ArduinoEthernetShield 29
Arduino WiFi Shield
Arduino WiFi Shield 101 30
有批 Wifi 晶片好便宜,有需要就打這個電話吧
31
Arduino Yún
32
MAC 位址
無線基地台模式
arduino
http://www.codedata.com.tw/social-coding/arduino-yun-1-sketch-python-led 33
34
36
無線網卡模式
37
無線上傳 Sketch
38
39
void setup() {
pinMode(13, OUTPUT);
}
void loop() {
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
}
40
41
#include <Bridge.h>
char state[2];
void setup() {
pinMode(13, OUTPUT);
Bridge.begin();
}
void loop() {
Bridge.get("state", state, 2);
digitalWrite(13, atoi(state));
delay(500);
} 42
Python 點亮光明燈
43
44
import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
from bridgeclient import BridgeClient
state = sys.argv[1]
BridgeClient().put('state', state)
root@arduino:~# python lightUpL13.py 1
root@arduino:~# python lightUpL13.py 0
45
透過瀏覽器點光明燈
http://www.codedata.com.tw/social-coding/arduino-yun-2-
simplehttpserver-yunserver-yunclient/ 46
import sys
import SimpleHTTPServer
import SocketServer
sys.path.insert(0, '/usr/lib/python2.7/bridge/')
from bridgeclient import BridgeClient
class LedRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == '/ledOn':
BridgeClient().put('state', '1')
elif self.path == '/ledOff':
BridgeClient().put('state', '0')
self.path = '/led.html'
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
server = SocketServer.TCPServer(('0.0.0.0', 8000), LedRequestHandler)
server.serve_forever()
47
led.html
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-
type">
<title></title>
</head>
<body>
<p><a href="ledOn">On</a> <a href="ledOff">Off</a></p>
</body>
</html>
48
YunServer 與 YunClient
#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>
YunServer server;
void setup() {
pinMode(13,OUTPUT);
digitalWrite(13, HIGH);
Bridge.begin();
server.listenOnLocalhost();
server.begin();
digitalWrite(13, LOW);
}
49
void loop() {
YunClient client = server.accept();
if(client) {
process(client);
client.stop();
}
delay(500);
}
void process(YunClient client) {
String command = client.readStringUntil('\r');
if (command == "ledOn") {
digitalWrite(13, HIGH);
}
else if (command == "ledOff") {
digitalWrite(13, LOW);
}
}
50
網路小車
https://www.youtube.com/watch?v=w5cRFU_9a-0
https://gist.github.com/JustinSDK/0c1deeec201afb50a6ab
https://gist.github.com/JustinSDK/70c1152fe0d4d593e23a 51
雲端 IoT 服務
52
Thingspeak
http://community.thingspeak.com/tutorials/arduino/controlling-the-
arduino-yun-with-talkback/ 53
54
55
#include "Bridge.h"
#include "HttpClient.h"
//ThingSpeak Settings
String thingSpeakAPI = "api.thingspeak.com";
String talkBackAPIKey = "IIR7WFDPFM7DSHP9";
String talkBackID = "5129";
const int checkTalkBackInterval = 15 * 1000;
// Variable Setup
long lastConnectionTime = 0;
void setup() {
// Setup On-board LED
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
delay(1000);
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
Bridge.begin();
}
void loop() {
checkTalkBack();
delay(checkTalkBackInterval);
}
56
void checkTalkBack() {
HttpClient client;
String talkBackCommand;
char charIn;
String talkBackURL = "http://" + thingSpeakAPI + "/talkbacks/" +
talkBackID + "/commands/execute?api_key=" + talkBackAPIKey;
client.get(talkBackURL);
while (client.available()) {
charIn = client.read();
talkBackCommand += charIn;
}
if (talkBackCommand == “TURN_ON”) {
digitalWrite(13, HIGH);
}
else if (talkBackCommand == “TURN_OFF”) {
digitalWrite(13, LOW);
}
delay(1000);
}
57
Temboo
58
https://temboo.com/arduino/yun/getting-started 59
60
61
/*
IMPORTANT NOTE about TembooAccount.h
TembooAccount.h contains your Temboo account information and must be included
alongside your sketch. To do so, make a new tab in Arduino, call it TembooAccount.h,
and copy this content into it.
*/
#define TEMBOO_ACCOUNT "caterpillar" // Your Temboo account name
#define TEMBOO_APP_KEY_NAME "myFirstApp" // Your Temboo app key name
#define TEMBOO_APP_KEY "e2f55cf1c2524ae59e70a89d3f96f831" // Your Temboo app key
/*
The same TembooAccount.h file settings can be used for all Temboo SDK sketches.
Keeping your account information in a separate file means you can share the
main .ino file without worrying that you forgot to delete your credentials.
*/
TembooAccount.h
62
#include <Bridge.h>
#include <Temboo.h>
#include "TembooAccount.h" // contains Temboo account information, as described below
int numRuns = 1; // Execution count, so this doesn't run forever
int maxRuns = 10; // Maximum number of times the Choreo should be executed
void setup() {
Serial.begin(9600);
// For debugging, wait until the serial console is connected
delay(4000);
while(!Serial);
Bridge.begin();
}
void loop() {
if (numRuns <= maxRuns) {
Serial.println("Running GetWeatherByAddress - Run #" + String(numRuns++));
TembooChoreo GetWeatherByAddressChoreo;
// Invoke the Temboo client
GetWeatherByAddressChoreo.begin();
// Set Temboo account credentials
GetWeatherByAddressChoreo.setAccountName(TEMBOO_ACCOUNT);
GetWeatherByAddressChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
GetWeatherByAddressChoreo.setAppKey(TEMBOO_APP_KEY);
// Set Choreo inputs
GetWeatherByAddressChoreo.addInput("Address", "Taipei");
// Identify the Choreo to run
GetWeatherByAddressChoreo.setChoreo("/Library/Yahoo/Weather/GetWeatherByAddress");
// Run the Choreo; when results are available, print them to serial
GetWeatherByAddressChoreo.run();
while(GetWeatherByAddressChoreo.available()) {
char c = GetWeatherByAddressChoreo.read();
Serial.print(c);
}
GetWeatherByAddressChoreo.close();
}
Serial.println("Waiting...");
delay(30000); // wait 30 seconds between GetWeatherByAddress calls
}
透過 USB 連接
TembooAccount.ino
63
64
Parse for IoT
65
https://www.parse.com/apps/quickstart#embedded/arduinoyun 66
67
草稿碼 → Include Library… → Manage Libraries…
parse
安裝 Parse Arduino SDK
68
69
70
#include <Bridge.h>
String revision = "1.0.2-1_ar71xx";
String location =
"https://raw.githubusercontent.com/ParsePlatform/parse-embedded-
sdks/1.0.2/yun/linux_package/";
void downloadPackage(String file) {
Serial.println("Download: " + location + file + revision + ".ipk");
Process p;
p.begin("curl");
p.addParameter("--stderr");
p.addParameter("-");
p.addParameter("-#");
p.addParameter("-s");
p.addParameter("-S");
p.addParameter("-k");
p.addParameter("-o");
p.addParameter("/tmp/" + file + revision + ".ipk");
p.addParameter(location + file + revision + ".ipk");
p.run();
while (p.available()) {
Serial.print((char)p.read());
}
}
71
void installPackage(String file) {
Serial.println("Install: /tmp/" + file + revision + ".ipk");
Process p;
p.begin("opkg");
p.addParameter("install");
p.addParameter("--force-reinstall");
p.addParameter("--force-downgrade");
p.addParameter("/tmp/" + file + revision + ".ipk");
p.run();
while(p.available()) {
Serial.print((char)p.read());
}
}
void setup() {
Bridge.begin();
Serial.begin(115200);
while(!Serial);
Serial.println("Downloading packages");
downloadPackage("parse-embedded_");
downloadPackage("parse-embedded-yun_");
Serial.println("Installing packages");
installPackage("parse-embedded_");
installPackage("parse-embedded-yun_");
Serial.println("\nDone.");
} 72
73
儲存物件
#include <Bridge.h>
#include <Parse.h>
void setup() {
// Initialize digital pin 13 as an output.
pinMode(13, OUTPUT);
// Initialize Bridge
Bridge.begin();
// Initialize Serial
Serial.begin(9600);
while (!Serial); // wait for a serial connection
Serial.println("Parse Starter Project");
// Initialize Parse
Parse.begin("dOpHkBs6A2XOToydYC7r7r1BmFxCgd6nU7JQ85Fw",
"BGyFLJuHJvje0LB6Ms9ZN30Mh1DfoKE43V3bq3FN");
74
ParseObjectCreate create;
create.setClassName("TestObject");
create.add("foo", "bar");
ParseResponse response = create.send();
Serial.println("\nResponse for saving a TestObject:");
Serial.print(response.getJSONBody());
if (!response.getErrorCode()) {
String objectId = response.getString("objectId");
Serial.print("Test object id:");
Serial.println(objectId);
} else {
Serial.println("Failed to save the object");
}
response.close(); // Do not forget to free the resource
}
75
76
Push 通知 #include <Bridge.h>
#include <Parse.h>
void setup() {
pinMode(13, OUTPUT);
Bridge.begin();
Serial.begin(9600);
while (!Serial);
Serial.println("Parse Starter Project");
Parse.begin("dOpHkBs6A2XOToydYC7r7r1BmFxCgd6nU7JQ85Fw",
"BGyFLJuHJvje0LB6Ms9ZN30Mh1DfoKE43V3bq3FN");
// Start push service
Parse.startPushService();
Serial.print("Push Installation ID:");
Serial.println(Parse.getInstallationId());
}
77
void loop() {
// Check if there is a new push
// A push with message {"alert":"A test push from Parse!"}
// will turn on LED for 3 seconds
if (Parse.pushAvailable()) {
ParsePush push = Parse.nextPush();
String message = push.getJSONBody();
Serial.print("New push message size: ");
Serial.println(message.length());
Serial.print("New push message content: ");
Serial.println(message);
String command = push.getString("alert");
if (command == "A test push from Parse!") {
digitalWrite(13, HIGH); // turn on LED
delay(3000); // wait 3 seconds
digitalWrite(13, LOW); // turn off LED
}
// NOTE: ensure to close current push message
// otherwise next push won't be available
push.close();
}
}
78
79
80
參考
• IoT 和 Big Data 商機的迷思
• Arduino、Web 到 IoT
81