iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 22
3
IoT

IoT沒那麼難!新手用JavaScript入門做自己的玩具~系列 第 23

[Day 22]-用JS控制Arduino吧!偵測老闆的一個Move~薪水小偷必備 - Johnny Five 之 Motion 動作感測器 - 實務應用(?)篇

  • 分享至 

  • xImage
  •  

IoT沒那麼難!新手用 JavaScript 入門做自己的玩具!(iT邦幫忙鐵人賽系列書)

★本系列文章已集結成冊,和系列文不同的是:

  • 本書使用大量的圖解來說明LED系列、多種感測器等原理。
  • 補足系列文程式碼的解說,增加逐行程式碼的詳細解說!
  • 全彩的書籍,用圖解的方式,讓讀者來理解Johnny-Five各種API的功能與效果,讓你不會只讀文字看到想睡覺而學不起來。

歡迎大家做出自己想要的玩具,為了樂趣而學習,讓學習變成你的樂趣!ヽ(・×・´)ゞ
讓Arduino也能用JavaScript創造出屬於自己的作品!

★購書連結-天瓏網路書局:
https://www.tenlong.com.tw/products/9789864345328

《IoT沒那麼難!新手用 JavaScript 入門做自己的玩具!(iT邦幫忙鐵人賽系列書)》
博客來、金石堂、momo、誠品、PChome、讀冊,均有販售喔!─=≡Σ((( つ•̀ω•́)つ
ISBN:9789864345328

本文先聲明為教學用途,不負任何責任(欸?

昨天主要講解PIR的工作原理和測試、實驗一下,
今天要來作一點小應用! ヽ(・×・´)ゞ

下音樂 again ~
登登楞登~登登~ (多拉A夢的音效)**

「老 闆 移 動 偵 測 器」~ ( σ՞ਊ ՞)σ

※使用前請詳閱公開說明書,請保證工作進度超前在使用本產品,本產品不負被抓包相關責任。(被打)

謎之音:這有什麼好做的....不就人體偵測嗎...ಠಠ
本魯:當然要加一點花樣騙騙人啊...欸不對...應該是發揮才能才對 ...

故事是這樣開始的…

因為我的 PIR Sensor 是從 Webduino 買豪華套件包來的,
發現我的 PIR Sensor 不能調觸發模式,就不能做更好玩的應用了...嗚嗚QQ...(以後會改善的Orz

所以既然不能調觸發模式,那就想別的方法吧~

又是靈光一閃過!(✪ω✪)
科技始於人性,人性始於墮性(?
像我們開發者整天坐在辦公室,需求一直改一直改,不如等到完全定案之後再開發
等待的時間又要假裝有在上班,實際上我就不說了...XD
所以研發了這個東西!

我想的功能是:

當薪水小偷可以不用很緊張,老闆快走過來時即時開啟 Stack overflow 或是 MDN 假裝在查Doc!(´≖◞౪◟≖)

發生事件情境設定:

當老闆快要走到我的位子的時候 → 人體感測器感測到老闆 → motionstart事件 → 透過 Socket 給前端資料 → 紀錄資料並開啟預設「看起來認真上班的網頁」。

恩~ 計画通り!ᕙ(˵ ಠ ਊ ಠ ˵)ᕗ

接下來跟著我一起浪費才能吧~ヽ(・×・´)ゞ
謎之音:又來了....(ㆆᴗㆆ)

補充說明 - Events

首先補充一下昨天的沒有仔細說到的 Events 部分
觸發 Johnny-Five Motion 物件後,會 retrun 資料物件

{
  // 時間戳
  timestamp: 1570416994150,
  // 偵測動作狀態,若有動作則返回布林值 `true` , 反則返回布林值 `false`
  detectedMotion: true,
  // 是否校準,已校準則返回布林值 `true` , 反則返回布林值 `false`
  isCalibrated: true
}

處理精度為毫秒的時間戳 - timestamp

這邊要注意的 Johnny-Five 返回的 timestamp13位數的時間戳

13 位數的時間戳精度為「毫秒
10 位數的時間戳精度則是「

但 JavaScript 處理的是10位的時間戳,要怎麼辦呢?

本魯宅:因為現在用不到毫秒等級那麼細的時間戳,只好切掉了!(≖_≖)✧

使用 Javascript 的字串處理 substr 函式 ,截取從 0~10 的字元就好

// 返回一個從指定位置開始的指定長度的子字串
String.substr(指定開始位置,截取長度);

MDN - String.prototype.substr()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr

但這邊又要注意了!!
因為 Johnny-Five 回傳的 timestamp 型別是 Number 而不是 String
直接用 substr() 函式擷取字元的話,會因為型別不對而報錯!

範例說明:

motion.on('motionstart', function(data) {
  timestamp = data.timestamp;
  console.log(typeof timestamp); // Number
});


substr() 因為型別不對而報錯!

轉型 - 從數字轉成字串

所以我們要把 Johnny-Five 吐出的時間戳轉為字串型別(String),在用 substr() 截取時間戳字串!

測試看看!

這樣就可以取出時間戳來轉換成人讀的時間了~(ง๑ •̀_•́)ง

下個步驟!拆解各個事件返回值

剛剛提到物件中, Johnny-Five 還會返回 isCalibrateddetectedMotion 物件,這兩個物件的值都是布林值 true / false

我們先了解物件的意義:

  • isCalibrated
    isCalibratedmotion.on('calibrated', function() { }); 一樣都只會在一開始做一次,當第一次發生目標物移動時則偵測訊號成功,isCalibrated 返回就會 true 值;
    之後觸發的 motion 動作,不管是 start 還是 end 的都會看到 isCalibrated 值都是 true

  • detectedMotion
    當目標物有移動動作,PIR Sensor 偵測到時便會回傳 detectedMotionture,就字面上的意思來說就是「偵測到動作了!」;
    當目標物停止移動動作,會回傳 detectedMotionfalse,意思來說就是「剛剛的偵測到的動作停止了!」。

不同的事件返回物件值

但每個觸發不同的事件,回傳的也會不一樣,

'calibrated' 校準事件
function data 不會回傳物件值,事件 'calibrated' 就表示只是一個狀態!

motion.on('calibrated', function(data) {
   console.log(data);
   console.log('calibrated');
 });

'motionstart' 偵測到動作事件

motion.on('motionstart', function(data) {
  console.log(data);
  console.log('motionstart');
});

此事件會 function data 返回

  • 偵測到動作的時間戳
  • detectedMotion 返回 true
  • isCalibrated 返回 true
{
  timestamp: 1570420021897,
  detectedMotion: true,
  isCalibrated: true
}

'motionend' 沒有偵測到動作了

motion.on('motionend', function(data) {
  console.log(data);
  console.log('motionstart');
});

此事件會 function data 返回

  • 動作停止的時間戳
  • detectedMotion 返回 false
  • isCalibrated 返回 true
{
  timestamp: 1570420021897,
  detectedMotion: false,
  isCalibrated: true
}

完整的一個循環~


講好多....終於要來實作啦~

程式碼很簡單,我們透過JavaScript window.open() 事件來實現這個應用~(ง๑ •̀_•́)ง

後端部分:

後端程式碼

var io = require('socket.io');
var express = require('express');
var five = require('johnny-five');

var board = new five.Board();
var app = express();

app.use(express.static('www'));
var server = app.listen(3000, function() {
  console.log('connected!');
});

var sio = io(server);

board.on('ready', function() {
  var motion = new five.Motion({
    pin: '7',
    freq: 250,
  });

  sio.on('connection', function(socket) {
    motion.on('calibrated', function() {
      //PIR Sensor Ready
      console.log('準備好啦!');
    });

    motion.on('motionstart', function(data) {
      // 偵測到有生物在動,觸發事件
      console.log('偵測到老闆!');
      socket.emit('startData', {
        // socket 傳送資料給前端
        isAction: data,
      });
    });
  });
});

前端部分

HTML 網頁就隨便裝飾一下,目的只是要開啟 Socket 連線而已

HTML

<body>
  <div class="container">
    <h2 class="p-5">老 闆 移 動 偵 測</h2>
  </div>
  <nav class="navbar navbar-light bg-light fixed-bottom">
    IoT沒那麼難!新手用JavaScript入門做自己的玩具 系列文 Tzeng,Ying-Chi
  </nav>
  <script src="/socket.io/socket.io.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  <script src="index.js"></script>
</body>

JavaScript

var socket = io.connect();

socket.on('startData', function(data) {
  //接收到偵測資料
  motionData = data.isAction;
  // 時間戳處理
  // 先處理數字轉字串 motionData.timestamp + ''
  // 接下來分割 10位數時間戳
  // 在用 parseInt() 函式轉回數字型別
  timestamp = parseInt((motionData.timestamp + '').substr(0, 10));
  // 取得是否偵測到動作
  isMotion = motionData.detectedMotion;
  // 轉換成人看的時間格式
  humanCanReadTime = getTime(timestamp);

  if (isMotion === true) {
    // 當老闆來時,在新分頁打開裝認真的網頁
    window.open(
      'https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array',
      '_blank',
    );
    // 印出時間點
    $('.container').append(
      '<div class="alert alert-danger boss-alert" role="alert">老闆出現於 <span class="time">' +
        humanCanReadTime +
        '</span> !</div>',
    );
  }
  // 時間戳格式轉換
  function getTime(timestamp) {
    var time = new Date(timestamp * 1000);
    var h = time.getHours();
    var min = time.getMinutes();
    var s = time.getSeconds();

    h = checkTime(h);
    min = checkTime(min);
    s = checkTime(s);

    timeStr = h + ':' + min + ' ' + s + '秒';

    return timeStr;
  }
  function checkTime(i) {
    if (i < 10) {
      i = '0' + i;
    } // add zero in front of numbers < 10
    return i;
  }
});

來Demo看看吧!!ヽ(・×・´)ゞ

Demo

想必大家都知道要如何寫出這麼棒的應用了吧~(才沒有!!
那今天就先到這囉~謝謝收看啦~─=≡Σ((( つ•̀ω•́)つ

文後

我絕對不是會用這種東西的工程師!不要誤會我 XDDD


本系列的程式碼皆會上傳到 GitHub 上開源

2019ironman-JS-IoT :
https://github.com/tinatyc/2019ironman-JS-IoT

喜歡按個星星吧~乾蝦乾蝦<(_ _)>


團隊系列文:

CSScoke - 金魚都能懂的這個網頁畫面怎麼切 - 金魚都能懂了你還怕學不會嗎
Hina Hina - 陣列大亂鬥
阿斬 - Python 程式交易 30 天新手入門
Clarence - LINE bot 好好玩 30 天玩轉 LINE API
塔塔默 - 用Python開發的網頁不能放到Github上?Lektor說可以!!
Vita Ora - 好 Js 不學嗎 !? JavaScript 入門中的入門。


同步連載於blogger-King 學習前端之人生


上一篇
[Day 21]-用JS控制Arduino吧!喵的一個Move!Hold住你的動作 - Johnny Five 之 Motion 動作感測器
下一篇
[Day 23]-用JS控制Arduino吧!三軸一起來,速度與激情!- Johnny Five 之 Accelerometer 三軸加速度計
系列文
IoT沒那麼難!新手用JavaScript入門做自己的玩具~33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

1
Wen Chien
iT邦新手 4 級 ‧ 2019-10-07 17:59:27

老闆看到你在看這個Youtube頻道應該要感到欣慰啊!

優質好頻道!馬上寄給老闆教育訓練一下/images/emoticon/emoticon37.gif

0
阿展展展
iT邦好手 1 級 ‧ 2019-10-20 01:09:34

太葉配惹ㄅ /images/emoticon/emoticon37.gif

不會啊 我平常就在看/images/emoticon/emoticon42.gif

我要留言

立即登入留言