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ラボデジタルサイネージ18】部屋の明るさを表示する「BrightnessRModule」

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の影を実装

作るもの

明るさのセンサ「CdSセル」を使い、明るさを計測できるようにします。

0037.png

画像の準備

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

background_bright.jpg

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

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

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

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 BRIGHTNESS_PATH = "brightness/"; /* 追加 */
final String DUMMY_PATH = "dummy/";

/* 略 */

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

DigitalSignage.pde
/* 略 */

/* ここから追加 */
// BrightnessRModule
PGraphics brightnessBackgroundBright;
PGraphics brightnessBackgroundNotBright;
/* ここまで追加 */

/* 略 */

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

DigitalSignage.pde
/* 略 */

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

/* 略 */

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

Initialize.pde
/* 略 */

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

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

/* 略 */

BrightnessRModule用関数と変数の準備

新しいファイルRM_Brightness.pdeを作ります。
BrightnessRModuleの描画用関数drawBrightnessRModule()、温度取得用の関数updateBrightness()を作ります。

RM_Brightness.pde
void drawBrightnessRModule(Area area) {
  
}

boolean updateBrightness() {
  return false;
}

値が更新されたことを示す変数、一定の基準値以上の明るさかを示す変数、明るさを0〜100%で示した変数を定義します。

DigitalSignage.pde
/* 略 */

// BrightnessRModule
SPI spi; /* 追加 */
boolean isBright = true; /* 追加 */
boolean isUpdatedBrightness = false; /* 追加 */
float brightnessRate = 0.0; /* 追加 */
PGraphics brightnessBackgroundBright;
PGraphics brightnessBackgroundNotBright;

/* 略 */

CdSセルからの値を取得するため、SPIという通信方式を使用します(本記事では詳細を割愛します)。

電子部品の配置

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

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

CdSセルと330Ω抵抗、ジャンパワイヤを下図のように配置します。

IMG_2207.jpg

ラズパイで値を取得するには、CdSセルを直接つなぐだけでなく、A/D変換した値を取り出す必要があります。
そこで、A/D変換用の電子部品「MCP3002」を使います。

MCP3002とジャンパワイヤを下図のように配置してください。
MCP3002の上下を間違えないようにしてください。ショートして起動しなくなります。

IMG_2208.jpg

ラズパイのGPIOピンに接続するために、ジャンパワイヤを4本接続します。

  • 左の上から1番目のピンは、19番ピン(GPIO10)に接続します。
  • 左の上から2番目のピンは、21番ピン(GPIO09)に接続します。
  • 左の上から3番目のピンは、23番ピン(GPIO11)に接続します。
  • 右の上から4番目のピンは、24番ピン(GPIO08)に接続します。

IMG_2209.jpg

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

CdSセルの値取得

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

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]);
  spi = new SPI(SPI.list()[0]); /* 追加 */
  spi.settings(500000, SPI.MSBFIRST, SPI.MODE0); /* 追加 */

  initialize();
}

/* 略 */

関数updateBrightness()内で、GPIOピンに送られてきた値を取得する処理を記述します。
MCP3002とのSPI通信を開始するとき、ラズパイからMCP3002に2byteの値を送ります。
その後に2byteの値が得られます。
2byteに含まれる16bitのうち、明るさの値としては、右から10bitの値(10進数になおすと、0〜1023)を使います。

得られた明るさの値が300以上のとき、「明るい」(isBright: true)という判定にします。

明るさの値は、割合(0〜100%)に換算します。

RM_Brightness.pde
boolean updateBrightness() {
  try {
    byte[] out = { byte(0x68), byte(0x00) };
    byte[] in = spi.transfer(out);
    int brightnessValue = ((in[0] << 8) + in[1]) & 0x3FF;
    isBright = (300 <= brightnessValue);
    brightnessRate = brightnessValue*100 / 1023.0;
    println("updateBrightness(): brightnessValue=" + brightnessValue,
              "brightnessRate=" + brightnessRate + "%",
              "isBright=" + isBright);
  } catch (Exception e) {
    return false;
  }
  
  return true;
}

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

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

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

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

  /* 略 */

BrightnessRModuleの描画

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

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

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

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

0038e.png

0037.png

関数moduleSize()をBrightnessRModuleに対応させます。
BrightnessRModuleのサイズは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;
  if (module == RModule.Brightness) return Size.S; /* 追加 */
  return Size.S;
}

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

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

/* 略 */

モジュールの背景と、明るさの値を表示します。

RM_Brightness.pde
void drawBrightnessRModule(Area area) {
  RModule module = RModule.Brightness;
  Size size = moduleSize(module);
  
  int x = layoutGuideX(area);
  int y = layoutGuideY(area);
  int w = moduleWidth(size);
  int h = moduleHeight(size);
  
  /* ここから追加 */
  if (isBright) {
    image(brightnessBackgroundBright, x, y, w, h);
  } else {
    image(brightnessBackgroundNotBright, x, y, w, h);
  }

  if (isUpdatedBrightness) {
    drawText(LEFT, BASELINE, WHITE_COLOR, 32, "明るさ", x+50, y+50);
    // 温度表示
    drawText(CENTER, BASELINE, WHITE_COLOR, 96, int(brightnessRate)+"%", 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, "BrightnessModule\nデータを取得できません", x+w/2, y+h/2);
  }
  /* ここまで追加 */
}

関数drawBrightnessRModule()が実装できたので、関数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);
    drawBrightnessRModule(Area.area2); /* 追加 */
    drawTwitterRModule(Area.area3);
    drawOpenCloseRModule(Area.area5);
  } else if (nowPageID == 2) {
    drawFullImageModule(adImage[0]);
  }
  drawDateModule();
  drawLocationModule();
  drawProgressBarModule();
  drawPageControlModule();
}

/* 略 */

実行してみると、明るさが表示されるようになっているはずです。
CdSセルを手で覆うと、値の変化が確認できるでしょう。

0037.png

最後に

これで、部屋の明るさを表示する「BrightnessRModule」が実装できました。
ReplaceableModuleは、BrightnessRModuleをもって全て完成しました!
次は、**起動画面を表示する「LaunchingScreenModule」**を作ってみましょう。

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?