4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Web屋の電子工作DIY:夜更かしテレビを罰金性にして、早起き生活を手に入れる②

Posted at

今回の内容

夜更かしテレビ罰金制度導入ツール.jpg

以下の順番で記載中。

前回光センサーの値をPythonで取得していたのですが、せっかくなので使ってみたかったNode.jsに切り替えてWebサイトを作りたいと思います。
今回はNode.jsの導入〜光センサーの値を画面表示するところまでです。

Node.jsフレームワークexpress+mongoDBを設定

設定の方法については色んなサイトに載っているのでそちらにまわします。
前回やったようにMacとRaspberryPiをLanで接続してターミナルで作業しました。
mongoDBの起動コマンドメモ:

mongod --dbpath ~/tmp/mongodb --fork --logpath ~/tmp/mongodb/log

参考サイト・書籍:

UIとDB構成を決めて作る

普通にサイトとか作る考えるのと同じですが、いちおうログ的に手順を残しておきます。

表示する内容を文字で書き出す

  • 現在の状態+α
    -- 待機中・・監視開始までの時間
    -- 停止中・・停止した時間
    -- 監視中・・現在ONの場合:残ON時間/現在OFFの場合は最後についていた時間

  • 履歴
    1日ごとの課金額

  • 今までの総課金額

UIをざっくり描いてみる

こんな感じで!やってることがうざ行為なのでUIのかわいさでカバーします。
DSC_0574.JPG

DB構成を考える

mongoDB

あんまり考える余地もないですが、せっかくなのでmongoDBについてはざーっと調べました。
RDBとだいぶ違っておもしろいですね。
MongoDBの薄い本
この本が知りたいことに一番答えてくれたように思います。

コレクション(テーブル)決定

必要な情報は今のところ履歴のとこだけかなあと思うので、以下のように登録するようにします。
pay_history

pay_date : String,
pay_count : 32-bit integer

実装しなきゃいけない動作を確認

で、ここまで作って何しなきゃいけないんだっけ・・?を忘れかけたのでいったん実装をちゃんと言語化しました。

※RaspberryPiのcronで0:30に以下を起動するようにセット
Loop開始
 光センサー:TVのON/OFF状態を取得
 重さセンサー:貯金箱の重さを取得 ★まだ
 if (重さが変わっていたら)
  15分のタイマーをセットして抜ける(15分後にLoopを開始)
  (!Webサイト更新:時間)
 else
  TVがONの状態の場合はOFFにする(赤外線を利用) ★まだ
  if (1.5H以上OFFのまま OR 5:00を過ぎている)
    Loopを抜けて終了する
    (!Webサイト更新:ステータス)
  else
    3分のタイマーをセットして抜ける(3分後にLoopを開始)
    (!Webサイト更新:時間)

あ、ちょっといろいろ遠いと今更気づく。。

Web画面を作る

こういうときはテンションのあがるところから着手します。
というわけで、画面のviewを作成しました。

Bootstrapを導入してViewを作成

公式サイトからBootstrapをローカルにダウンロードします。
linuxコマンドでダウンロードしたファイルをRaspberryPiに転送します。

scp (ローカルファイル) pi@(IPアドレス):(あげたいディレクトリ)

Node.jsのviewsの中でマークアップしていきます。

/views
├── index.ejs
└── partials
  ├── header.ejs
  └── footer.ejs
/public
├── css
| ├── style.css
| └── bootstrap.min.css

├── js
|  ├── bootstrap.min.js
|  ├── footerFixed.js
|  └── jquery-1.12.3.min.js

└── images
  └── 使った画像

引っかかったところ:

  • ejsでHTML埋め込むのにprintとかechoとか使ったらコンパイルエラーになった。。
    地味に悩んだのですが、結論は「<%- (html)%>」で埋め込み可能です。

  • 基本的にターミナルでの作業になるので、今更ながらVimをちゃんと使ってみることにしました。
    地味に難しくて時間食った・・でも慣れると愛せるエディタな気がします。
    チートシート(と、シートを貼るために初めて使ったマスキングテープ)が良い仕事する。
    参考サイト:僕がサクラエディタからVimに乗り換えるまで

最終的にこんな感じに。
画像はfirealpacaというフリーソフトで適当に書きました。
色はなんとなくガチャ●ンと同色です。
スクリーンショット 2016-04-08 14.45.15.png

光センサーの値を取得して表示する

長くなったので終わりにして次の記事にいきたい気持ちなのですが、
これだけで終わるとWebの解説になってしまうので電子工作に戻ります。。

参考サイト:Arduino UNO R3でとったセンサーデータをC3.jsでグラフ表示する

Socket.ioの導入

package.jsonにいくつか追加して、npm installを実行します。
いちおうdependenciesだけ載せておきます。

package.json
  "dependencies": {
    "ejs": "~2.3.3",
    "express": "~4.13.1",
    "express-session": "^1.13.0",
    "johnny-five": "*",
    "mongoose": "^4.4.10",
    "serialport": "*",
    "socket.io": "*"
  }

もろもろ変更

引っかかったところ:

  • Device or Firmware Error A timeout occurred while connecting to the Board.
    というエラーがでて結構長いこと引っかかり、、以下2点を実施することで解決しました。
    ・スケッチをFirmataの例に書き換える
    ・以下が出たのを確認してからアクセスする
      Device(s) /dev/ttyACM0
      Connected /dev/ttyACM0
      Repl Initialized

  • Express×Socket.ioによるファイルの分割方法に迷って。。
    基本的に『はじめてのNode.js』に従いました。
    ただExpress3の書き方になっているので、4に合わせてちょっと変更する必要があります。

※以下、主要なところだけ。。node app.jsで実行します。

app.js
var http = require('http'),
    express = require('express'),
    routes = require('./routes/index'),
    path = require('path'),
    arduino = require('./sockets/arduino'),
    app,
    server,
    io;

app = express();
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');

app.use(express.static(__dirname + '/public'));

app.get('/', routes);

server = http.createServer(app);
io = require('socket.io').listen(server);

server.listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

io.sockets.on('connection', arduino.onConnection);
models/Arduino.js
var five = require('johnny-five');
var board = new five.Board();
var sensor;

module.exports = function(socket){
  board.on('ready', function() {
    sensor = new five.Sensor({
        pin: 'A0',
        freq: 100
    });
    board.repl.inject({
        pot: sensor
    });
    
    sensor.scale(0, 100).on('data', function() {
      var value = this.value;
      if(socket){
        socket.emit('get A0', { value: value });
      }
    });
  });
};
routes/index.js
var express = require('express');
var router = express.Router();
var CalendarView = require("../models/CalendarView");
var ArduinoTest = require("../models/ArduinoTest");

/* GET home page. */
router.get('/', function(req, res, next) {
    var ar = new ArduinoTest();
    var clview = new CalendarView(new Date);
    res.render("index", {
      title: "夜更かしテレビは罰金性",
      clview: clview.getView(),
      ar: ar.getData()
    });
});

module.exports = router;
sockets/arduino.js
var arduino = require('../models/Arduino.js');

exports.onConnection = function (socket) {
  arduino(socket);
};
public/socket-arduino.js
(function(){
  var socket;

  $(document).ready(function () {
     socket = io.connect();

     socket.on('connected', function(data) {
     });

     socket.on('get A0', function(data){
      $('#arduino-test').html(data['value']);
     });
  });
})();
views/header.ejs
(前略)
    <script type="text/javascript" src="/socket.io/socket.io.js"></script>
    <script>
      var socket = io();
    </script>
    <script type="text/javascript" src="/js/socket-arduino.js"></script>
(略)

蛇足な感想

いったりきたりして読みにくい記事かもと思うけれど、書きながら実践すると「やりきらなきゃ!」と思えたり、どこで見てこうしたんだっけ・・?と忘れていたことなんかを思い出せたりして予想以上に便利です。(自分の記憶って本っ当に頼りにならない・・)
まだまだがんばるぞ。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?