LoginSignup
5
2

More than 1 year has passed since last update.

長期休暇 ~大人の自由研究~ 【obniz】で【ドットアニメーション】に挑戦してみた結果

Posted at

IoTってよく時事問題とかに出るけど実際に何が出来るのか分からない。
偶然にも実家に使われていないobnizがあったので、色々触ってみた。
スターターキットの中で興味を引くものは「LEDマトリックス」「ブザー」だったので
「LEDマトリックス」を使って何かを表現しようという内容。

「LEDマトリックス」を使って「ドットアニメーション」を作る

何はともあれまずは結果↓

テキストをそのまま描画する方法だと文字が潰れたり正直イマイチだったので、
ドット単位で点灯させる方法を選択した。

初心者でも何とか打開出来た方法

コード
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@3.16.0/obniz.js"></script>
</head>
<body>

<div id="obniz-debug"></div>

<script>
  var obniz = new Obniz("OBNIZ_ID_HERE");
  obniz.onconnect = async function () {

  var matrix = obniz.wired("Keyestudio_HT16K33", {
        gnd: 0,
        vcc: 1,
        sda: 2,
        scl: 3      
  });

  await matrix.init(8);
  await matrix.brightness(7);
  await matrix.clear();

  const ctx = await obniz.util.createCanvasContext(
    matrix.width,
    matrix.height
  );
  ctx.fillStyle = "white";  


  //ドットアニメーション(晴れ)
  for(let i = 1; i<10; i++) {

    //wait処理  
    const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    await drawShine(ctx,matrix);
    await _sleep(500);
    await drawShine2(ctx,matrix);
    await _sleep(500);

  };
  await drawShine(ctx,matrix);

  //点滅表示 雨
  for(let i = 1; i<5; i++) {

    //wait処理  
    const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    await _sleep(500);
    await drawRain(ctx,matrix);
    await _sleep(1000);
    await drawNull(ctx,matrix);
    await _sleep(500);

  };
  await drawRain(ctx,matrix);

  //点滅表示 曇り
  for(let i = 1; i<5; i++) {

    //wait処理  
    const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    await _sleep(500);
    await drawClowd(ctx,matrix);
    await _sleep(1000);
    await drawNull(ctx,matrix);
    await _sleep(500);

  };
  await drawClowd(ctx,matrix);

  //点滅表示 雪
  for(let i = 1; i<5; i++) {

    //wait処理  
    const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    await _sleep(500);
    await drawSnow(ctx,matrix);
    await _sleep(1000);
    await drawNull(ctx,matrix);
    await _sleep(500);

  };
  await drawSnow(ctx,matrix);


  //関数の定義
  //雨マーク
  async function drawRain(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(2,0,4,1)
    _ctx.fillRect(1,1,1,1)
    _ctx.fillRect(6,1,1,1)
    _ctx.fillRect(0,2,1,1)
    _ctx.fillRect(7,2,1,1)
    _ctx.fillRect(0,3,8,1)
    _ctx.fillRect(4,4,1,1)
    _ctx.fillRect(4,5,1,1)
    _ctx.fillRect(2,6,1,1)
    _ctx.fillRect(4,6,1,1)
    _ctx.fillRect(3,7,1,1)

    _matrix.draw(_ctx);
  }

  //点滅用空白
  async function drawNull(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _matrix.draw(_ctx);
  }

  //晴れマーク
  async function drawShine(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(0,0,6,1)
    _ctx.fillRect(0,1,6,1)
    _ctx.fillRect(7,1,1,1)
    _ctx.fillRect(0,2,6,1)
    _ctx.fillRect(0,3,5,1)
    _ctx.fillRect(7,3,1,1)
    _ctx.fillRect(0,4,4,1)
    _ctx.fillRect(0,5,3,1)
    _ctx.fillRect(6,5,1,1)
    _ctx.fillRect(5,6,1,1)
    _ctx.fillRect(1,7,1,1)
    _ctx.fillRect(3,7,1,1)

    _matrix.draw(_ctx);
  }

  //晴れマーク2
  async function drawShine2(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(0,0,6,1)
    _ctx.fillRect(0,1,6,1)
    _ctx.fillRect(7,0,1,1)
    _ctx.fillRect(0,2,6,1)
    _ctx.fillRect(0,3,5,1)
    _ctx.fillRect(7,2,1,1)
    _ctx.fillRect(0,4,4,1)
    _ctx.fillRect(0,5,3,1)
    _ctx.fillRect(5,5,1,1)
    _ctx.fillRect(6,6,1,1)
    _ctx.fillRect(0,7,1,1)
    _ctx.fillRect(2,7,1,1)
    _ctx.fillRect(4,7,1,1)
    _ctx.fillRect(7,4,1,1)

    _matrix.draw(_ctx);
  }

  //曇りマーク
  async function drawClowd(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(2,1,3,1)
    _ctx.fillRect(1,2,1,1)
    _ctx.fillRect(5,2,1,1)
    _ctx.fillRect(1,3,1,1)
    _ctx.fillRect(4,3,3,1)
    _ctx.fillRect(0,4,1,3)
    _ctx.fillRect(3,4,1,1)
    _ctx.fillRect(7,4,1,3)
    _ctx.fillRect(1,7,6,1)

    _matrix.draw(_ctx);
  }

  //雪マーク
  async function drawSnow(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(3,0,2,1)
    _ctx.fillRect(2,1,1,3)
    _ctx.fillRect(5,1,1,3)
    _ctx.fillRect(3,3,2,1)
    _ctx.fillRect(1,4,1,3)
    _ctx.fillRect(6,4,1,3)
    _ctx.fillRect(2,7,4,1)

    _matrix.draw(_ctx);
  }

}

</script>
</body>
</html>


関数の中にある_ctx.fillRect(x,x,x,x)がLEDマトリックスの点灯位置を表しているようで
引数は横軸座標・縦軸座標・座標からの横軸への幅・座標から縦軸への幅となっている模様。
とは言え設計図も描かずに出来ないので、仕事でよく使うExcelを利用してみた。
image.png
ピクロスのような設計図を作成して、ドット絵とコードを紐付け。
視覚的に確認しながらコードを作成することが出来た。

アニメーションを付けた方法

パラパラ漫画GIFアニメの要領で、ドット絵の差分を用意し交互に表示させた。
image.png
image.png

作った「アニメーション」をどう活かしたのか

最終的な成果物↓

天気のAPIから情報を取得して、
obnizのディスプレイには:地域・日付・時刻・天気・気温・室温を表示
LEDディスプレイには取得した天気情報に合致するアニメーションを表示
LED信号は天気に対応した色を点灯させた
温度センサーも付けて、室温を取得している

詳細について

こちらのサイト様を参考にさせてもらいました。

コード
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@3.16.0/obniz.js"></script>
</head>
<body>

<script>
  var obniz = new Obniz("OBNIZ_ID_HERE");
  obniz.onconnect = async function () {

  var matrix = obniz.wired("Keyestudio_HT16K33", {
        gnd: 0,
        vcc: 1,
        sda: 2,
        scl: 3      
  });

  await matrix.init(8);
  await matrix.brightness(7);
  await matrix.clear();

  const ctx = await obniz.util.createCanvasContext(
    matrix.width,
    matrix.height
  );
  ctx.fillStyle = "white";

  var light = obniz.wired("Keyestudio_TrafficLight", {
    gnd: 7,
    green: 8,
    yellow: 9,
    red: 10
  });

  var tempsens = obniz.wired("Keyestudio_TemperatureSensor", { signal: 4, vcc: 5, gnd: 6 });
  var API_KEY = 'APIキー'
  var city = '取得する地域名';
  var url = 'http://api.openweathermap.org/data/2.5/forecast?q=' + city + ',jp&units=metric&APPID=' + API_KEY;
  var i = 2;
  var Wdata;
  var ienaka = await tempsens.getWait();

  async function sendWeather(data,i) {
      var Week = new Array("","","","","","","");
      var date = new Date (data.list[i].dt_txt);
      var month = date.getMonth()+1;
      var day = month + "/" + date.getDate() + "/" + Week[date.getDay()] + date.getHours() + ":00";
      var nowWeather = data.list[i].weather[0].main;
      var nowTemp = Math.round(data.list[i].main.temp);

      obniz.display.clear();
      obniz.display.print(city);
      obniz.display.print(day);
      obniz.display.print("室温 🏠 " + Math.floor(ienaka) + "");
      switch(nowWeather){
        case "Clear" :
          obniz.display.print("晴れ ☀ " + nowTemp + "");
          light.green.on();

          //ドットアニメーション(晴れ)
          for(let i = 1; i<10; i++) {

            //wait処理  
            const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

            await drawShine(ctx,matrix);
            await _sleep(500);
            await drawShine2(ctx,matrix);
            await _sleep(500);

          };
          await drawShine(ctx,matrix);

          break;
        case "Rain" :
          obniz.display.print("雨 ☂ " + nowTemp + "");
          light.red.on();

          //点滅表示 雨
          for(let i = 1; i<5; i++) {

            //wait処理  
            const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

            await _sleep(500);
            await drawRain(ctx,matrix);
            await _sleep(1000);
            await drawNull(ctx,matrix);
            await _sleep(500);

          };
          await drawRain(ctx,matrix);

          break;
        case "Clouds" :
          obniz.display.print("曇り ☁ " + nowTemp + "");
          light.yellow.on();

          //点滅表示 曇り
          for(let i = 1; i<5; i++) {

            //wait処理  
            const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

            await _sleep(500);
            await drawClowd(ctx,matrix);
            await _sleep(1000);
            await drawNull(ctx,matrix);
            await _sleep(500);

          };
          await drawClowd(ctx,matrix);

          break;
        case "Snow" :
          obniz.display.print("雪 ⛄ " + nowTemp + "");
          light.red.on();
          //点滅表示 雪
          for(let i = 1; i<5; i++) {

            //wait処理  
            const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

            await _sleep(500);
            await drawSnow(ctx,matrix);
            await _sleep(1000);
            await drawNull(ctx,matrix);
            await _sleep(500);

          };
          await drawSnow(ctx,matrix);

          break;
        default:
          obniz.display.print(nowWeather + " " + nowTemp + "");
      }
  }

  //openweathermapへアクセス
  $.ajax({
    url: url,
    dataType: "json",
    type: 'GET',
  })
  //検索成功時にはページに結果を反映
  .done(function(data) {
    sendWeather(data,i);
    Wdata = data;
    console.log(Wdata);
  })
  //検索失敗時にはその旨をディスプレイに表示
  .fail(function(data) {
    obniz.display.clear();
    obniz.display.print("Error");
  });
  obniz.switch.onchange = function(state) {
    if(state == "right"){
      if(i == 8)
        i=0;
      else
        i+=1;
    }else if(state == "left"){
      if(i == 0)
        i=8;
      else
        i-=1;
    }
    //sendWeather関数に取得したデータを引き渡す
    sendWeather(Wdata,i);
  }

  //関数の定義
  //雨マーク
  async function drawRain(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(2,0,4,1)
    _ctx.fillRect(1,1,1,1)
    _ctx.fillRect(6,1,1,1)
    _ctx.fillRect(0,2,1,1)
    _ctx.fillRect(7,2,1,1)
    _ctx.fillRect(0,3,8,1)
    _ctx.fillRect(4,4,1,1)
    _ctx.fillRect(4,5,1,1)
    _ctx.fillRect(2,6,1,1)
    _ctx.fillRect(4,6,1,1)
    _ctx.fillRect(3,7,1,1)

    _matrix.draw(_ctx);
  }

  //点滅用空白
  async function drawNull(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _matrix.draw(_ctx);
  }

  //晴れマーク
  async function drawShine(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(0,0,6,1)
    _ctx.fillRect(0,1,6,1)
    _ctx.fillRect(7,1,1,1)
    _ctx.fillRect(0,2,6,1)
    _ctx.fillRect(0,3,5,1)
    _ctx.fillRect(7,3,1,1)
    _ctx.fillRect(0,4,4,1)
    _ctx.fillRect(0,5,3,1)
    _ctx.fillRect(6,5,1,1)
    _ctx.fillRect(5,6,1,1)
    _ctx.fillRect(1,7,1,1)
    _ctx.fillRect(3,7,1,1)

    _matrix.draw(_ctx);
  }

  //晴れマーク2
  async function drawShine2(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(0,0,6,1)
    _ctx.fillRect(0,1,6,1)
    _ctx.fillRect(7,0,1,1)
    _ctx.fillRect(0,2,6,1)
    _ctx.fillRect(0,3,5,1)
    _ctx.fillRect(7,2,1,1)
    _ctx.fillRect(0,4,4,1)
    _ctx.fillRect(0,5,3,1)
    _ctx.fillRect(5,5,1,1)
    _ctx.fillRect(6,6,1,1)
    _ctx.fillRect(0,7,1,1)
    _ctx.fillRect(2,7,1,1)
    _ctx.fillRect(4,7,1,1)
    _ctx.fillRect(7,4,1,1)

    _matrix.draw(_ctx);
  }

  //曇りマーク
  async function drawClowd(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(2,1,3,1)
    _ctx.fillRect(1,2,1,1)
    _ctx.fillRect(5,2,1,1)
    _ctx.fillRect(1,3,1,1)
    _ctx.fillRect(4,3,3,1)
    _ctx.fillRect(0,4,1,3)
    _ctx.fillRect(3,4,1,1)
    _ctx.fillRect(7,4,1,3)
    _ctx.fillRect(1,7,6,1)

    _matrix.draw(_ctx);
  }

  //雪マーク
  async function drawSnow(_ctx, _matrix) {
    await _matrix.clear();
    await _ctx.clearRect(0, 0, _matrix.width, _matrix.height);

    _ctx.fillRect(3,0,2,1)
    _ctx.fillRect(2,1,1,3)
    _ctx.fillRect(5,1,1,3)
    _ctx.fillRect(3,3,2,1)
    _ctx.fillRect(1,4,1,3)
    _ctx.fillRect(6,4,1,3)
    _ctx.fillRect(2,7,4,1)

    _matrix.draw(_ctx);
  }

}

</script>
</body>
</html>

IoT機器を触ってみて

はっきり言ってそんなに簡単ではないし、業務レベルにするには費用も嵩みそうな印象を受けた。
とは言え、インターネットを介して物理的な領域に干渉出来るというのは実感出来た。
触ってみて出来ることを知ったからこそ出るアイデアもあるはずだ。

5
2
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
5
2