Use Node.js DDP Client on Arduino Yun to Access Meteor Server

Use Node.js DDP Client on Arduino Yun to Access Meteor Server

概述

在Arduino Yun上安裝 Node.js, 並測試與 Meteor 經過 DDP Client 通信。html

所用硬件

  • Arduino Yun
  • SD Card(至少 2GB,我使用的是 8G )

所用軟件

PC 軟件: node

  • Arduino IDE
  • SSH Terminal(Putty / Screen)

升級 Arduino Yun固件

  1. 從站點上下載 Arduino Yun 最新的 openWRT 固件, 當前升級包的版本號是 YunSysupgradeImage_v1.5.3.zip。git

  2. 選用 MS-DOS 方式格式化 SD Card,將所下載的 ZIP 文件展開出的 bin 文件複製到 SD Card 的根文件夾下。github

  3. 將 SD Card 插入 Arduino Yun, 並從新啓動 Arduino Yun。正常狀況下,應該可以在 Web Page 點按 「RESET」 按鈕運行升級。web

RESET

也可以用 SSH 登錄後,先檢查一下 /mnt/sda1 文件夾下是否有升級文件,並運行下面命令。npm

# ls /mnt/sda1
    openwrt-ar71xx-generic-yun-16M-squashfs-sysupgrade.bin

    # run-sysupgrade /mnt/sda1/openwrt-ar71xx-generic-yun-16M-squashfs-sysupgrade.bin
  1. 升級完畢後。選擇 ArduinoYun 的初始 WIFI。並經過 Web 頁面訪問 192.168.240.1。設置 Arduino Yun 的網絡鏈接。

利用 SD Card 擴展 Arduino Yun 空間

Arduino Yun 的板上存儲僅有 16M,要想安裝不少其它地東西就必須利用 SD Card 擴展磁盤空間。參考連接json

  1. 從新啓動後,經過本地局域網。SSH 到 Arduino Yun上,檢查現有的分區狀況。websocket

    # df
    Filesystem           1K-blocks      Used Available Use% Mounted on
    rootfs                    7104       364      6740   5% /
    /dev/root                 7680      7680         0 100% /rom
    tmpfs                    30560       148     30412   0% /tmp
    tmpfs                      512         0       512   0% /dev
    /dev/mtdblock3            7104       364      6740   5% /overlay
    overlayfs:/overlay        7104       364      6740   5% /
    /dev/sda1              7746772      1008   7745764   0% /mnt/sda1
  2. 下載 YunDiskSpaceExpander.zipmarkdown

  3. 經過 USB 鏈接 Arduino Yun,打開 Arduino IDE 上傳此 ino 文件, 而後打開 Serial Monitor。在屏幕右下方選擇 「Newline」, 並依照提示進行操做。下面的操做記錄了我爲分區方式,供參考。需要注意的是,此處輸入的 4096 的意思是,將 4G 的空間保留爲 /mnt/sda1 下的數據存儲,剩下的空間留給根文件夾。cookie

    整個過程需要等待幾分鐘。

    Open the Serial Monitor and double check the dropdown menu "Newline" has been selected. This sketch will format your micro SD card and use it as additional disk space for your Arduino Yun. Please ensure you have ONLY your micro SD card plugged in: no pen drives, hard drives or whatever. Do you wish to proceed (yes/no)? yes Starting Bridge... Ready to install utility software. Please ensure your Arduino Yun is connected to internet. Ready to proceed (yes/no)?

    yes Updating software list... Software list updated. Installing software (this will take a while)... e2fsprogs mkdosfs fdisk rsync installed Proceed with partitioning micro SD card (yes/no)?

    yes Enter the size of the data partition in MB: 4096 Partitioning (this will take a while)... Micro SD card correctly partitioned Creating 'arduino' folder structure... Copying files from Arduino Yun flash to micro SD card... Enabling micro SD as additional disk space... enabled We are done! Yeah! Now press the YUN RST button to apply the changes.
  4. 按下 YUN RST 後等待系統全然從新啓動,再次檢查分區狀況,可以看到,Root 文件夾已經被放置在 /dev/sda2 下了,大小已經被擴大。

    # df
    Filesystem           1K-blocks      Used Available Use% Mounted on
    rootfs                 3556712    120920   3257464   4% /
    /dev/root                 7680      7680         0 100% /rom
    tmpfs                    30560       100     30460   0% /tmp
    tmpfs                      512         0       512   0% /dev
    /dev/sda2              3556712    120920   3257464   4% /overlay
    overlayfs:/overlay     3556712    120920   3257464   4% /
    /dev/sda1              4186104        12   4186092   0% /mnt/sda1

安裝 Node.js

確認 Arduino Yun 可以正常聯網,而後運行下面安裝 Node.js。 原文參考連接

# opkg update
# opkg install node

安裝完畢以後,可以用下面命令檢查 Node.js 成功安裝

# node -e "console.log('Hello_Yun')"
Hello_Yun

Arduino Yun 可用的所有 Package 可以在這裏找到。

您還可以依據需要,安裝不少其它的 Node.js 基礎包,好比:

# opkg install node-serialport
# opkg install node-noble

設置 Swap 區

Arduino Yun 提供的 Node.js 包很是有限。還需要經過 npm 安裝不少其它可擴展包。但是因爲 npm 所需的內存比較大,咱們必須打開 Swap 才幹夠順利運行,不然會報內存不足。

  1. 檢查現有的 Swap 設置

    # free -m
                 total         used         free       shared      buffers
    Mem:         61116        31712        29404            0         8364
    -/+ buffers:              23348        37768
    Swap:            0            0            0
  2. SSH 登錄後。建立 Swap 分區。這一步要等比較長的時間。

    # mkdir /swap
    
    # dd if=/dev/zero of=/swap/yunswapfile bs=1M count=1024
    1024+0 records in
    1024+0 records out
  3. 設置 Swapon。此時已經可以看到 Swap 區正確建立了。

    # mkswap /swap/yunswapfile
    # swapon /swap/yunswapfile
    
    # free -m
                total         used         free       shared      buffers
    Mem:         61116        59704         1412            0         7676
    -/+ buffers:              52028         9088
    Swap:      1048572            0      1048572
  4. 設置啓動時本身主動載入 Swap。從新啓動 Arduino Yun 後。Swap 區應該正常。

    # uci add fstab swap
    # uci set fstab.@swap[0].device=/swap/yunswapfile
    # uci set fstab.@swap[0].enabled=1
    # uci set fstab.@swap[0].fstype=swap
    # uci set fstab.@swap[0].options=default
    # uci set fstab.@swap[0].enabled_fsck=0
    # uci commit

安裝 DDP Client

此時,咱們再使用 npm 安裝 DDP Client。

我使用的 DDP Client 是 https://www.npmjs.com/package/ddp

# npm install ddp
# npm install underscore

# npm list
    /root
    ├─┬ ddp@0.11.0
    │ ├── ddp-ejson@0.8.1-3
    │ ├── ddp-underscore-patched@0.8.1-2
    │ ├─┬ faye-websocket@0.9.4
    │ │ └─┬ websocket-driver@0.5.4
    │ │   └── websocket-extensions@0.1.1
    │ └─┬ request@2.53.0
    │   ├── aws-sign2@0.5.0
    │   ├─┬ bl@0.9.4
    │   │ └─┬ readable-stream@1.0.33
    │   │   ├── core-util-is@1.0.1
    │   │   ├── inherits@2.0.1
    │   │   ├── isarray@0.0.1
    │   │   └── string_decoder@0.10.31
    │   ├── caseless@0.9.0
    │   ├─┬ combined-stream@0.0.7
    │   │ └── delayed-stream@0.0.5
    │   ├── forever-agent@0.5.2
    │   ├─┬ form-data@0.2.0
    │   │ └── async@0.9.2
    │   ├─┬ hawk@2.3.1
    │   │ ├── boom@2.7.2
    │   │ ├── cryptiles@2.0.4
    │   │ ├── hoek@2.14.0
    │   │ └── sntp@1.0.9
    │   ├─┬ http-signature@0.10.1
    │   │ ├── asn1@0.1.11
    │   │ ├── assert-plus@0.1.5
    │   │ └── ctype@0.5.3
    │   ├── isstream@0.1.2
    │   ├── json-stringify-safe@5.0.1
    │   ├─┬ mime-types@2.0.13
    │   │ └── mime-db@1.11.0
    │   ├── node-uuid@1.4.3
    │   ├── oauth-sign@0.6.0
    │   ├── qs@2.3.3
    │   ├── stringstream@0.0.4
    │   ├── tough-cookie@1.2.0
    │   └── tunnel-agent@0.4.0
    └── underscore@1.8.3

使用 DDP Client 訪問 Meteor

下面的參考實現展現了怎樣用 DDP Client 與 Meteor 交互。

var DDPClient = require("ddp"),
    _ = require('underscore');

var ddpclient = new DDPClient({
    // url: 'ws://192.168.199.240:3000/websocket'
    url: 'ws://mcotton-01.chinacloudapp.cn/websocket'
});

var useremail = "iasc@163.com";
var pwd = "123456";

var user_id = null, token = null;

var appkit_weather_station, myappkit_weather_station, my_app_kit_id;
var data_observer, control_observer;

/*
 * Connect to the Meteor Server
 */
ddpclient.connect(function (error, wasReconnect) {
    // If autoReconnect is true, this callback will be invoked each time
    // a server connection is re-established

    if (error) {
        console.log("DDP connection error!");
        return;
    }

    if (wasReconnect) {
        console.log("Reestablishment of a connection.");
    }

    console.log("connected!");

    ddpclient.call("login", [
        {user: {email: useremail}, password: pwd}
    ], function (err, result) {
        console.log(result);
        user_id = result.id;
        token = result.token;

        if (token) {
            console.log("Logined!", user_id, token);

            //var observer = ddpclient.observe("appkits");

            /*
             * Subscribe to a Meteor Collection
             */
            ddpclient.subscribe(
                "appkits",                  // name of Meteor Publish function to subscribe to
                [],                       // any parameters used by the Publish function
                function () {             // callback when the subscription is complete
                    console.log("appkits all ==> ", ddpclient.collections.appkits);

                    appkit_weather_station = _(ddpclient.collections.appkits).findWhere({name: 'Weather Station'});
                    console.log("appkits weather_station  ==> ", appkit_weather_station);
                    console.log("appkits weather_station id ==> ", appkit_weather_station._id);

                    // Create myAppKit

                    var myAppKit = ddpclient.call(
                        'myAppKitInsert',
                        [{
                            name: 'My Weather Station',
                            app_kit_id: appkit_weather_station._id
                        }],
                        function (err, result) {
                            console.log('myAppKitInsert, error: ' + error);
                            console.log('myAppKitInsert, result: ' + result._id);

                            my_app_kit_id = result._id;

                            /*
                             * Subscribe to a Meteor Collection
                             */
                            ddpclient.subscribe(
                                "myappkits",                  // name of Meteor Publish function to subscribe to
                                [user_id],          // any parameters used by the Publish function
                                function () {             // callback when the subscription is complete
                                    console.log("myappkits all ==> ", ddpclient.collections.myappkits);

                                    console.log("appkit_weather_station id ==> ", appkit_weather_station._id);

                                    myappkit_weather_station = _(ddpclient.collections.myappkits).filter({_id: my_app_kit_id});
                                    console.log("myappkits weather_station  ==> ", myappkit_weather_station);
                                }
                            );

                            ddpclient.subscribe(
                                "dataevents",                  // name of Meteor Publish function to subscribe to
                                [user_id],          // any parameters used by the Publish function
                                function () {             // callback when the subscription is complete
                                    console.log("dataevents all ==> ", ddpclient.collections.dataevents);
                                }
                            );

                            ddpclient.subscribe(
                                "controlevents",                  // name of Meteor Publish function to subscribe to
                                [user_id],          // any parameters used by the Publish function
                                function () {             // callback when the subscription is complete
                                    console.log("controlevents all ==> ", ddpclient.collections.controlevents);
                                }
                            );

                            /*
                             * observe DataEvents
                             */
                            data_observer = ddpclient.observe("dataevents");

                            data_observer.added = function (id) {
                                console.log("[ADDED] to " + data_observer.name + ":  " + id);

                                var event = _(ddpclient.collections.dataevents).findWhere({_id: id});
                                console.log("[ADDED] dataevents ", event)
                            };

                            /*
                             * observe ControlEvents
                             */
                            control_observer = ddpclient.observe("controlevents");

                            control_observer.added = function (id) {
                                console.log("[ADDED] to " + control_observer.name + ":  " + id);

                                var event = _(ddpclient.collections.controlevents).findWhere({_id: id});
                                console.log("[ADDED] controlevents ", event)
                            };

                            /*
                             * Send new Control Event to Server
                             * */
                            var newControlEvent = ddpclient.call(
                                'controlEventInsert',
                                [{
                                    my_app_kit_id: my_app_kit_id,
                                    control_name: "Status",
                                    control_value: "true"
                                }],
                                function (err, result) {
                                    console.log('controlEventInsert, error: ' + error);
                                    console.log('controlEventInsert, result: ' + result._id);
                                });
                        }
                    );
                }
            );
        }
    });

    ////Debug information
    //
    //ddpclient.on('message', function (msg) {
    //    console.log("ddp message: " + msg);
    //});

    /*
     ddpclient.on('socket-close', function (code, message) {
     console.log("Close: %s %s", code, message);
     });

     ddpclient.on('socket-error', function (error) {
     console.log("Error: %j", error);
     });
     */

    // close

    setTimeout(function () {
        // observer.stop();
        ddpclient.close();
    }, 5000);

});

代碼地址

https://github.com/iascchen/arduino_study/tree/master/src/yun_ddp


轉載請註明出處

Author : iascchen(at)gmail(dot)com

Date : 2015-6-3

Github : https://github.com/iascchen/arduino_study

新浪微博 : @問天鼓

相關文章
相關標籤/搜索