本記事は、株式会社 函館ラボラトリが運営する「Bラボ」における、大人向け「看板アプリ(デジタルサイネージ)を作るコース」用教材テキストです。
- 【Bラボデジタルサイネージ1】Processing+ラズパイでデジタルサイネージを作る!
- 【Bラボデジタルサイネージ2】ラズパイ初期設定
- 【Bラボデジタルサイネージ3】準備プログラム作成&機能実現の方針決定
- 【Bラボデジタルサイネージ4】レイアウトの基準になるグリッドを表示する「GridModule」
- 【Bラボデジタルサイネージ5】レイアウトの基準になる枠を表示する「PlaceholderModule」
- 【Bラボデジタルサイネージ6】画像を全画面表示する「FullImageModule」
- 【Bラボデジタルサイネージ7】ページの自動切り替え
- 【Bラボデジタルサイネージ8】設置されている場所の名前を表示する「LocationModule」
- 【Bラボデジタルサイネージ9】現在の時間を表示する「DateModule」
- 【Bラボデジタルサイネージ10】ページ切り替えの時間が分かる「ProgressBarModule」
- 【Bラボデジタルサイネージ11】現在の表示中のページが分かる「PageControlModule」
- 【Bラボデジタルサイネージ12】現在の天気を表示する「WeatherRModule」
- 【Bラボデジタルサイネージ13】直近2件のバス時刻表を表示する「BusRModule」
- 【Bラボデジタルサイネージ14】ごみ出しカレンダーを表示する「GomiRModule」
- 【Bラボデジタルサイネージ15】(発展編)ツイートを表示する「TwitterRModule」
- 【Bラボデジタルサイネージ16】開店/閉店を表示する「OpenCloseRModule」(本記事)
- 【Bラボデジタルサイネージ17】部屋の温度を表示する「TemperatureRModule」
- 【Bラボデジタルサイネージ18】部屋の明るさを表示する「BrightnessRModule」
- 【Bラボデジタルサイネージ19】起動画面を表示する「LaunchingScreenModule」
- 【Bラボデジタルサイネージ20】RModuleの影を実装
作るもの
スライドスイッチを使い、開店/閉店の表示を切り替えられるようにします。
画像の準備
OpenCloseRModuleの背景画像には、下の画像を使用します。
画像を2回保存し、それぞれ「background_open.jpg」と「background_close.jpg」という名前をつけます。
(.png形式など別の形式の場合は、.jpg形式に変換してください。)
Processingの画面上のタブで、「スケッチ > スケッチフォルダーを開く」を選ぶと、開いている.pdeファイルが一覧で表示されます。
「data」フォルダの中に、新たに「openclose」フォルダを作ってください。
先ほど名前をつけて保存した「background_open.jpg」と「background_close.jpg」を「data/openclose」フォルダの直下においてください。(ドラッグ&ドロップ)
ここで新しく作った「data/openclose」フォルダの位置を示すパスを、定数として定義します。
/* 略 */
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 DUMMY_PATH = "dummy/";
/* 略 */
OpenCloseRModuleの背景を保持する変数を定義します。
/* 略 */
/* ここから追加 */
// OpenCloseModule
PGraphics openCloseBackgroundOpen;
PGraphics openCloseBackgroundClose;
/* ここまで追加 */
/* 略 */
RModuleのリストに、OpenCloseRModuleを表す「OpenClose」を追加します。
/* 略 */
enum RModule {
Weather,
Bus,
Gomi,
Twitter,
OpenClose /* 追加 */
}
/* 略 */
background_open.jpg
とbackground_close.jpg
を用いて、モジュールの背景画像を生成します。
initializeRModuleBackground()
内で実装します。
/* 略 */
void initializeRModuleBackground() {
/* 中略 */
gomiBackground.rect(0, 0, w, h);
gomiBackground.endDraw();
gomiBackground.mask( sizeToModuleMask( moduleSize(module) ) );
/* ここから追加 */
module = RModule.OpenClose;
w = moduleWidth( moduleSize(module) );
h = moduleHeight( moduleSize(module) );
back = loadImage(OPENCLOSE_PATH + "background_open.jpg");
openCloseBackgroundOpen = createGraphics(w, h);
openCloseBackgroundOpen.beginDraw();
openCloseBackgroundOpen.colorMode(HSB, 360, 100, 100, 100);
openCloseBackgroundOpen.image( pImageCut(back, CENTER, CENTER, w, h) , 0, 0);
openCloseBackgroundOpen.fill(0, 0, 0, 40);
openCloseBackgroundOpen.noStroke();
openCloseBackgroundOpen.rect(0, 0, w, h);
openCloseBackgroundOpen.endDraw();
openCloseBackgroundOpen.mask( sizeToModuleMask( moduleSize(module) ) );
back = loadImage(OPENCLOSE_PATH + "background_close.jpg");
openCloseBackgroundClose = createGraphics(w, h);
openCloseBackgroundClose.beginDraw();
openCloseBackgroundClose.colorMode(HSB, 360, 100, 100, 100);
openCloseBackgroundClose.image( pImageCut(back, CENTER, CENTER, w, h) , 0, 0);
openCloseBackgroundClose.fill(0, 0, 0, 40);
openCloseBackgroundClose.noStroke();
openCloseBackgroundClose.rect(0, 0, w, h);
openCloseBackgroundClose.endDraw();
openCloseBackgroundClose.mask( sizeToModuleMask( moduleSize(module) ) );
/* ここまで追加 */
/* 略 */
OpenCloseRModule用関数と変数の準備
新しいファイルRM_OpenClose.pde
を作ります。
OpenCloseRModuleの描画用関数drawOpenCloseRModule()
、ごみカレンダー更新用の関数updateOpenClose()
を作ります。
void drawOpenCloseRModule(Area area) {
}
boolean updateOpenClose() {
return false;
}
開店/閉店の状態を表す変数、値が更新されたことを示す変数を定義します。
/* 略 */
// OpenCloseModule
boolean isUpdatedOpenClose = false; /* 追加 */
boolean isOpen = false; /* 追加 */
PGraphics openCloseBackgroundOpen;
PGraphics openCloseBackgroundClose;
/* 略 */
電子部品の配置
電子部品を組み替えるときは、ラズパイの電源を切り、電源ケーブルをコンセントから抜いてください。
以降、ラズパイと電子部品を接続するときのピンの番号は、下記サイトのGPIOピンの配置カードを参考にしてください。
まずブレッドボードへ電気を送るための配線を作ります。
ブレッドボードの「+」と「-」にそれぞれ、ジャンパワイヤをさします。
「+」は2番ピン(5V)、「-」は6番ピン(GND)に繋いでください。
スライドスイッチ、3本のジャンパワイヤ、1kΩ抵抗を下図のように配置します。
1kΩ抵抗に繋いだジャンパワイヤは、ラズパイの16番ピン(GPIO23)に繋いでください。
これで電子部品の配置が完了しました。
スライドスイッチの値取得
ラズパイのGPIOピン経由で値をやり取りするため、ライブラリprocessing.io.*
をインポートしておきます。
import processing.io.*;
/* 略 */
今回、スライドスイッチと値をやりとりするピンは「GPIO23」のため、番号を定数として定義しておきます。
/* 略 */
// OpenCloseModule
boolean isUpdatedOpenClose = false;
boolean isOpen = false;
PGraphics openCloseBackgroundOpen;
PGraphics openCloseBackgroundClose;
final int SWITCH_PIN = 23; /* 追加 */
/* 略 */
関数setup()
内で、GPIOピンから入力を受け取るための設定をします。
/* 略 */
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); /* 追加 */
initialize();
}
/* 略 */
関数updateOpenClose()
内で、GPIOピンに送られてきた値を取得する処理を記述します。
スライドスイッチがONのときGPIO.LOW
、OFFのときGPIO.HIGH
という値が取得できます。
boolean updateOpenClose() {
try {
if (GPIO.digitalRead(SWITCH_PIN) == GPIO.LOW) {
isOpen = true;
} else {
isOpen = false;
}
} catch (Exception e) {
return false;
}
return true;
}
関数updateOpenClose()
が実装できたので、この関数を呼び出すようにします。
スライドスイッチから値を取得するタイミングは、以下の2つとします。
- デジタルサイネージを起動したとき
- 毎秒
void initialize() {
initializeDate();
initializeImage();
initializeGrid();
initializePlaceholder();
initializeRModuleBackground();
isUpdatedWeather = updateWeather();
isUpdatedBus = updateBus();
isUpdatedGomi = updateGomi();
isUpdatedTwitter = updateTwitter();
isUpdatedOpenClose = updateOpenClose(); /* 追加 */
}
/* 略 */
/* 略 */
void updateDatas() {
updateDate();
isUpdatedOpenClose = updateOpenClose(); /* 追加 */
/* 略 */
OpenCloseRModuleの描画
データが変数に代入できている状態になったので、画面上に表示するところまで実装します。
置換可能なReplaceableModuleを実装するとき、最低限定めなければいけないことは以下です。
- 描画時の基準となるエリア(Area.area1〜Area.area8のいずれか)
- 描画時のサイズ(Size.S〜Size.Lのいずれか)
まずはOpenCloseRModuleの描画時の基準となるエリアについて説明します。
OpenCloseRModuleの描画の基準になるのは、8つある表示エリアのうちArea.area5です。
関数moduleSize()
をOpenCloseRModuleに対応させます。
TwitterRModuleのサイズはSize.M
です。
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;
return Size.S;
}
次に関数drawOpenCloseRModule()
を実装します。
Area.area5
の左上の座標、OpenCloseRModuleの幅と高さを取得します。
void drawOpenCloseRModule(Area area) {
RModule module = RModule.OpenClose;
Size size = moduleSize(module);
int x = layoutGuideX(area);
int y = layoutGuideY(area);
int w = moduleWidth(size);
int h = moduleHeight(size);
}
/* 略 */
スイッチからデータを取得できなかったときの表示を実装します。
void drawOpenCloseRModule(Area area) {
RModule module = RModule.OpenClose;
Size size = moduleSize(module);
int x = layoutGuideX(area);
int y = layoutGuideY(area);
int w = moduleWidth(size);
int h = moduleHeight(size);
/* ここから追加 */
if (isUpdatedOpenClose) {
} else {
fill(0, 0, 0, 50);
noStroke();
rect(x, y, w, h, MODULE_RECT_ROUND);
drawText(CENTER, CENTER, WHITE_COLOR, 24, "OpenCloseModule\nデータを取得できません", x+w/2, y+h/2);
}
/* ここまで追加 */
}
スイッチの値によって、OpenCloseRModuleの背景とテキストを切り替えられるようにします。
void drawOpenCloseRModule(Area area) {
RModule module = RModule.OpenClose;
Size size = moduleSize(module);
int x = layoutGuideX(area);
int y = layoutGuideY(area);
int w = moduleWidth(size);
int h = moduleHeight(size);
/* ここから追加 */
if (isOpen) {
image(openCloseBackgroundOpen, x, y, w, h);
} else {
image(openCloseBackgroundClose, x, y, w, h);
}
/* ここまで追加 */
if (isUpdatedOpenClose) {
/* ここから追加 */
if (isOpen) {
drawText(LEFT, BASELINE, WHITE_COLOR, 128, "OPEN", x+50, y+50);
drawText(LEFT, BASELINE, WHITE_COLOR, 32, "開店しています。", x+50, y+250);
} else {
drawText(LEFT, BASELINE, WHITE_COLOR, 128, "CLOSE", x+50, y+50);
drawText(LEFT, BASELINE, WHITE_COLOR, 32, "閉店しています。\n14時から開店します。", x+50, y+250);
}
/* ここまで追加 */
} else {
fill(0, 0, 0, 50);
noStroke();
rect(x, y, w, h, MODULE_RECT_ROUND);
drawText(CENTER, CENTER, WHITE_COLOR, 24, "OpenCloseModule\nデータを取得できません", x+w/2, y+h/2);
}
}
drawOpenCloseRModuleが実装できたので、関数drawModules()
内で実装します。
/* 略 */
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();
drawTwitterRModule(Area.area3);
drawOpenCloseRModule(Area.area5); /* 追加 */
} else if (nowPageID == 2) {
drawFullImageModule(adImage[0]);
}
drawDateModule();
drawLocationModule();
drawProgressBarModule();
drawPageControlModule();
}
/* 略 */
実行してスイッチを切り替えると、表示が変わるようになっているはずです。
最後に
これで開店/閉店を表示する「OpenCloseRModule」が実装できました。
次は、**部屋の温度を表示する「TemperatureRModule」**を作ってみましょう。