0
0

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 1 year has passed since last update.

【Bラボデジタルサイネージ17】部屋の温度を表示する「TemperatureRModule」

Last updated at Posted at 2021-11-12

本記事は、株式会社 函館ラボラトリが運営する「Bラボ」における、大人向け「看板アプリ(デジタルサイネージ)を作るコース」用教材テキストです。

  1. 【Bラボデジタルサイネージ1】Processing+ラズパイでデジタルサイネージを作る!
  2. 【Bラボデジタルサイネージ2】ラズパイ初期設定
  3. 【Bラボデジタルサイネージ3】準備プログラム作成&機能実現の方針決定
  4. 【Bラボデジタルサイネージ4】レイアウトの基準になるグリッドを表示する「GridModule」
  5. 【Bラボデジタルサイネージ5】レイアウトの基準になる枠を表示する「PlaceholderModule」
  6. 【Bラボデジタルサイネージ6】画像を全画面表示する「FullImageModule」
  7. 【Bラボデジタルサイネージ7】ページの自動切り替え
  8. 【Bラボデジタルサイネージ8】設置されている場所の名前を表示する「LocationModule」
  9. 【Bラボデジタルサイネージ9】現在の時間を表示する「DateModule」
  10. 【Bラボデジタルサイネージ10】ページ切り替えの時間が分かる「ProgressBarModule」
  11. 【Bラボデジタルサイネージ11】現在の表示中のページが分かる「PageControlModule」
  12. 【Bラボデジタルサイネージ12】現在の天気を表示する「WeatherRModule」
  13. 【Bラボデジタルサイネージ13】直近2件のバス時刻表を表示する「BusRModule」
  14. 【Bラボデジタルサイネージ14】ごみ出しカレンダーを表示する「GomiRModule」
  15. 【Bラボデジタルサイネージ15】(発展編)ツイートを表示する「TwitterRModule」
  16. 【Bラボデジタルサイネージ16】開店/閉店を表示する「OpenCloseRModule」
  17. 【Bラボデジタルサイネージ17】部屋の温度を表示する「TemperatureRModule」(本記事)
  18. 【Bラボデジタルサイネージ18】部屋の明るさを表示する「BrightnessRModule」
  19. 【Bラボデジタルサイネージ19】起動画面を表示する「LaunchingScreenModule」
  20. 【Bラボデジタルサイネージ20】RModuleの影を実装

作るもの

温度センサ「ADT7410」を使い、温度を計測をできるようにします。

0011.png

画像の準備

TemperatureRModuleの背景画像には、下の画像を使用します。

background.jpg

画像を保存し、それぞれ「background.jpg」という名前をつけます。
(.png形式など別の形式の場合は、.jpg形式に変換してください。)

Processingの画面上のタブで、「スケッチ > スケッチフォルダーを開く」を選ぶと、開いている.pdeファイルが一覧で表示されます。
「data」フォルダの中に、新たに「temperature」フォルダを作ってください。
先ほど名前をつけて保存した「background.jpg」を「data/temperature」フォルダの直下においてください。(ドラッグ&ドロップ)

ここで新しく作った「data/temperature」フォルダの位置を示すパスを、定数として定義します。

DigitalSignage.pde
/* 略 */

final String AD_PATH = "ad/";
final String WEATHER_PATH = "weather/";
final String BUS_PATH = "bus/";
final String GOMI_PATH = "gomi/";
final String TWITTER_PATH = "twitter/";
final String OPENCLOSE_PATH = "openclose/"
final String TEMPERATURE_PATH = "temperature/"; /* 追加 */
final String DUMMY_PATH = "dummy/";

/* 略 */

OpenCloseRModuleの背景を保持する変数を定義します。

DigitalSignage.pde
/* 略 */

/* ここから追加 */
// TemperatureRModule
PGraphics temperatureBackground;
/* ここまで追加 */

/* 略 */

RModuleのリストに、OpenCloseRModuleを表す「OpenClose」を追加します。

DigitalSignage.pde
/* 略 */

enum RModule {
  Weather,
  Bus,
  Gomi,
  Twitter,
  OpenClose,
  Temperature /* 追加 */
}

/* 略 */

background.jpgを用いて、モジュールの背景画像を生成します。
initializeRModuleBackground()内で実装します。

Initialize.pde
/* 略 */

void initializeRModuleBackground() {
  /* 中略 */
  openCloseBackgroundClose.rect(0, 0, w, h);
  openCloseBackgroundClose.endDraw();
  openCloseBackgroundClose.mask( sizeToModuleMask( moduleSize(module) ) );

  /* ここから追加 */
  module = RModule.Temperature;
  w = moduleWidth( moduleSize(module) );
  h = moduleHeight( moduleSize(module) );
  back = loadImage(TEMPERATURE_PATH + "background.jpg");
  temperatureBackground = createGraphics(w, h);
  temperatureBackground.beginDraw();
  temperatureBackground.colorMode(HSB, 360, 100, 100, 100);
  temperatureBackground.image( pImageCut(back, CENTER, CENTER, w, h) , 0, 0);
  temperatureBackground.fill(0, 0, 0, 40);
  temperatureBackground.noStroke();
  temperatureBackground.rect(0, 0, w, h);
  temperatureBackground.endDraw();
  temperatureBackground.mask( sizeToModuleMask( moduleSize(module) ) );
  /* ここまで追加 */

/* 略 */

TemperatureRModule用関数と変数の準備

新しいファイルRM_Temperature.pdeを作ります。
TemperatureRModuleの描画用関数drawTemperatureRModule()、温度取得用の関数updateTemperature()を作ります。

RM_Temperature.pde
void drawTemperatureRModule(Area area) {
  
}

boolean updateTemperature() {
  return false;
}

温度(摂氏)を表す変数、値が更新されたことを示す変数を定義します。

DigitalSignage.pde
/* 略 */

// TemperatureRModule
I2C i2c; /* 追加 */
boolean isUpdatedTemperature = false; /* 追加 */
float roomTempValue = 20.0; /* 追加 */
PGraphics temperatureBackground;

/* 略 */

温度センサの値を取得するため、I2Cという通信方式を使用します(本記事では詳細を割愛します)。

電子部品の配置

電子部品を組み替えるときは、ラズパイの電源を切り、電源ケーブルをコンセントから抜いてください。

以降、ラズパイと電子部品を接続するときのピンの番号は、下記サイトのGPIOピンの配置カードを参考にしてください。

まずブレッドボードへADT7410を配置します(4本のピンがはんだ付けされている前提です)。
ADT7410のピンの横には、3文字のアルファベットが印字されています。

「VDD」は、ブレッドボードの「+」に接続します。
「SCL」は、ラズパイの5番ピン(GPIO03、I2C)に接続します。
「SDA」は、ラズパイの3番ピン(GPIO02、I2C)に接続します。
「GND」は、ブレッドボードの「-」に接続します。

IMG_2206.jpg

これで電子部品の配置が完了しました。

温度センサの値取得

関数setup()内で、I2Cで入力を受け取るための設定をします。
接続されているデバイスのリストから、一番最初に出てくるデバイスの情報をi2cという変数に入れておきます。

DigitalSignage.pde
/* 略 */

void setup() {
  frameRate(1);
  noCursor();
  colorMode(HSB, 360, 100, 100, 100);
  WHITE_COLOR = color(0, 0, 100);
  NEARLY_WHITE_COLOR = color(100, 2, 98);
  NEARLY_GREEN_COLOR = color(100, 5, 98);
  BLACK_COLOR = color(0, 0, 0);
  LIGHT_COLOR = color(0, 0, 80);
  GRAY_COLOR = color(0, 0, 50);
  GREEN_COLOR = color(150, 100, 60);
  
  textFont(createFont("NotoSansCJKjp-Bold", 32));
  
  background = pImageCut(loadImage("background.jpg"), CENTER, CENTER, width, height);
  
  GPIO.pinMode(SWITCH_PIN, GPIO.INPUT);
  i2c = new I2C(I2C.list()[0]); /* 追加 */
  
  initialize();
}

/* 略 */

関数updateTemperature()内で、GPIOピンに送られてきた値を取得する処理を記述します。
温度センサとの通信を開始するときにbeginTransmission()、終了するときにendTransmission()を実行します。
通信開始時には、接続されている温度センサのアドレス0x48を指定します。

温度センサから値を取得するときには、「取得する値がどのような値か」を設定するための情報を書き込むことが必要です。
下記サイトの「動作設定レジスタ詳細」を参考にして、今回設定すべき内容を以下の2つとします。

  • 温度を、0.0078度の分解能(精密さ)で計測:bit7を1にする
  • 計測する頻度は、1秒に1回:bit6を1にする

上記2つを設定するために書き込むべき値は、11000000と分かります。
この数は16進数表記にすると0xC0となるので、write()0xC0を書き込みます。

RM_Temperature.pde
boolean updateTemperature() {
  try {
    i2c.beginTransmission(0x48);
    i2c.write(0xC0);
    byte[] v = i2c.read(2);
    i2c.endTransmission();
  } catch (Exception e) {
    roomTempValue = 0.0;
    return false;
  }
  
  return true;
}

0xC0を書き込んだ後、温度センサから16bit(2byte)の値を取得します。
この16bitの値をプログラムで変換し、摂氏の温度に変換します。

1byteの値が2つ、配列vに入っています。
16bitの値に変換するとき、v[0]に入っている8bitは上位8bit、v[1]に入っている8bitは下位8bitとして扱います。
v[0]の値は、8bitだけ左にビットシフトします。

変換した結果得られた値は、今回温度センサから取得した温度の分解能0.0078を掛けることで、摂氏の温度に変換することができます。

RM_Temperature.pde
boolean updateTemperature() {
  try {
    i2c.beginTransmission(0x48);
    i2c.write(0xC0);
    byte[] v = i2c.read(2);
    i2c.endTransmission();
    
    /* ここから追加 */
    int temp = ((v[0] & 0x1F) * 256 + (v[1] & 0xFF));
    if (4096 <= temp) {
      temp -= 8192;
    }
  
    roomTempValue = temp * 0.0078;
    /* ここまで追加 */
  } catch (Exception e) {
    roomTempValue = 0.0;
    return false;
  }
  
  return true;
}

関数updateTemperature()が実装できたので、この関数を呼び出すようにします。
温度センサから値を取得するタイミングは、以下の2つとします。

  • デジタルサイネージを起動したとき
  • 毎秒
Initialize.pde
void initialize() {
  initializeDate();
  initializeImage();
  initializeGrid();
  initializePlaceholder();
  initializeRModuleBackground();
  
  isUpdatedWeather = updateWeather();
  isUpdatedBus = updateBus();
  isUpdatedGomi = updateGomi();
  isUpdatedTwitter = updateTwitter();
  
  isUpdatedOpenClose = updateOpenClose();
  isUpdatedTemperature = updateTemperature(); /* 追加 */
}

/* 略 */
DigitalSignage.pde
/* 略 */

void updateDatas() {
  updateDate();
  isUpdatedOpenClose = updateOpenClose();
  isUpdatedTemperature = updateTemperature(); /* 追加 */

  /* 略 */

TemperatureRModuleの描画

データが変数に代入できている状態になったので、画面上に表示するところまで実装します。

置換可能なReplaceableModuleを実装するとき、最低限定めなければいけないことは以下です。

  • 描画時の基準となるエリア(Area.area1〜Area.area8のいずれか)
  • 描画時のサイズ(Size.S〜Size.Lのいずれか)

まずはTemperatureRModuleの描画時の基準となるエリアについて説明します。
TemperatureRModuleの描画の基準になるのは、8つある表示エリアのうちArea.area1です。

0038e.png

0189.png

関数moduleSize()をTemperatureRModuleに対応させます。
TwitterRModuleのサイズはSize.Sです。

DigitalSignage.pde
Size moduleSize(RModule module) {
  if (module == RModule.Weather) return Size.M;
  if (module == RModule.Bus) return Size.L;
  if (module == RModule.Gomi) return Size.M;
  if (module == RModule.Twitter) return Size.L;
  if (module == RModule.OpenClose) return Size.M;
  if (module == RModule.Temperature) return Size.S;
  return Size.S;
}

次に関数drawTemperatureRModule()を実装します。
Area.area1の左上の座標、TemperatureRModuleの幅と高さを取得します。

RM_Temperature.pde
void drawTemperatureRModule(Area area) {
  RModule module = RModule.Temperature;
  Size size = moduleSize(module);
  
  int x = layoutGuideX(area);
  int y = layoutGuideY(area);
  int w = moduleWidth(size);
  int h = moduleHeight(size);

/* 略 */

モジュールの背景と、温度の値を表示します。

RM_Temperature.pde
void drawTemperatureRModule(Area area) {
  RModule module = RModule.Temperature;
  Size size = moduleSize(module);
  
  int x = layoutGuideX(area);
  int y = layoutGuideY(area);
  int w = moduleWidth(size);
  int h = moduleHeight(size);
  
  /* ここから追加 */
  image(temperatureBackground, x, y, w, h);
    
  // モジュールの名前表示
  drawText(LEFT, BASELINE, WHITE_COLOR, 32, "室温", x+50, y+50);
  
  if (isUpdatedTemperature) {
    // 温度表示
    drawText(CENTER, BASELINE, WHITE_COLOR, 96, nf(roomTempValue, 0, 1)+"℃", x+w/2, y+150);
  } else {
    fill(0, 0, 0, 50);
    noStroke();
    rect(x, y, w, h, MODULE_RECT_ROUND);
    
    drawText(CENTER, CENTER, WHITE_COLOR, 24, "TemperatureModule\nデータを取得できません", x+w/2, y+h/2);
  }
  /* ここまで追加 */
}

関数drawTemperatureRModule()が実装できたので、関数drawModules()内で呼び出します。

DigitalSignage.pde
/* 略 */

void drawModules() {
  if (nowPageID == 0) {
    drawFullImageModule(background);
    drawGridModule();
    drawPlaceholderModule();
    drawWeatherRModule(Area.area1);
    drawBusRModule(Area.area3);
    drawGomiRModule(Area.area5);
  } else if (nowPageID == 1) {
    drawFullImageModule(background);
    drawGridModule();
    drawPlaceholderModule();
    drawTemperatureRModule(Area.area1); /* 追加 */
    drawTwitterRModule(Area.area3);
    drawOpenCloseRModule(Area.area5);
  } else if (nowPageID == 2) {
    drawFullImageModule(adImage[0]);
  }
  drawDateModule();
  drawLocationModule();
  drawProgressBarModule();
  drawPageControlModule();
}

/* 略 */

実行してみると、温度が表示されるようになっているはずです。
温度センサに指を触れると、徐々に温度が高くなっていく様子も確認できるでしょう。

0011.png

最後に

これで部屋の温度を表示する「TemperatureRModule」が実装できました。
次は、**部屋の明るさを表示する「BrightnessRModule」**を作ってみましょう。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?