シナリオで動くデジタルサイネージを作ってみよう!

デ ジタルサイネージは普及をしてきましたが、サイネージの端末が多くなればなるほど、そのコンテンツをローカルに持っておき、コンテンツを書き換える時には その端末の前まで行って、コンテンツを書き換えるのでは手間がかかり過ぎます。ということで、モバイル環境も簡単に利用できることですし、遠隔から表示順 を変更できるサイネージを作ってみよう。
今回は、ウェブでデジタルサイネージのコンテンツが作成されているものとして、接続先のウェブを切り替えることで、動的に変わるデジタルサイネージを実現したいと思います。

(1)シナリオに沿った接続先に接続するブラウザ(サイネージ)部分
(2)シナリオをウェブから取って来て処理する部分

のステップで作成してみよう。


図 完成予想図

(0)開発環境
開発環境としては以下のものを用います。

・デジタルサイネージ制御端末:Windows7 Professional
・開発言語:Visual Studio2008、Visual C#
・シナリオ管理サーバー:Windows7で動作する簡易Httpサーバー

(1)シナリオに沿った接続先に接続するブラウザの作成
C# のアプリケーションとしては、フォームアプリを選択し、フォームにWebBrowserコンポーネントを載せることで、ウェブのアクセスを実現することに します。また、定期的に切り替わる動作については、Timerコンポーネントを利用したいと思います。今回のアプリケーションでは、単純に一定の時間が経 過したら、表示画面を切り替えるという動作としたいと思います。

まず、VisualStudioでVC#のフォームアプリケーションを選択します。プロジェクトの名前は、ddigitalsignageとします。



フォー ムのサイズは、実際のサイネージの画面に合わせて変更する必要がありますが、ここでは、SVGAサイズ(800x600)程度にしておきましょう。サイズ は、フォームのプロパティのsize属性で変更できます。また、見栄えの話なのですが、画面のタイトルバーがあると格好が悪いので、タイトルバーをなくし ておきましょう。これは、ConsolBox属性をFalseにして、Text属性の値を消去することで実現できます。



次 に、フォームにWebBrowserコンポーネントを配置します。ツールボックスのWebBrowserコンポーネントをドラッグアンドドロップで、 フォーム画面に配置することができます。サイズは、特に何もしなければ、フォームに収まるように配置できるようですが、そうならない場合には、同じくプロ パティで適当なサイズにしておきます。
最後に、Timerコンポーネントを利用できるようにします。ツールボックスのTimerをドラッグし、そ のまま、フォームの画面にドロップすることで、使えるようになります。Timerを利用可能にするために、TimerのプロパティのEnabledを Trueに、また、画面表示の切り替えを秒単位にするように、Intervalの値を1000にしておきます。



次 に、起動時に最初のページが表示されるようにしておきます。起動時に処理したい内容は、フォームのLoadイベントを使うことで実現できます。デザイン画 面で、フォームを選択し、プロパティの雷マークを選択します。すると、一番上にLoadと表示されますので、そのLoadの部分をダブルクリックします。 すると、Loadのスタブがコードに表示されます。





では、初期画面として、大学のホームページを表示します。urlは、グローバル変数として、urlという変数を定義し、それを表示用に使用することとしました。

        // 変数の定義
        string url = "http://www.kait.jp/";

    (略)

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                webBrowser1.Navigate(new Uri(url));
            }
            catch
            {
            }
        }

ここまでで、一度アプリケーションを動かしてみましょう。大学のホームページは表示されたでしょうか。タイトルバーがないので少し操作しにくいですね。



では次に、画面が動的に変わる部分を追加します。処理としては、次のようにします。

(1)グローバル変数として時間のカウンタ(cnt1)、表示するURL(2つ:url1, url2)を定義
(2)時間をカウントし、10秒立ったら、URLをチェックし、URLを切り替える

まずは、これだけの処理とします。URLは、大学のページ以外に、Yahoo!のページをお借りしましょう。

    public partial class Form1 : Form
    {
        // 変数の定義
        int cnt1 = 0; // 画面切り替えようのカウンター
        string url = "http://www.kait.jp/";
        string url1 = "http://www.kait.jp/";
        string url2 = "http://www.yahoo.co.jp/";

Timerを使うには、デザイン画面のTimer1を選択し、プロパティの雷マークを選択します。そして、そこから、Tickを選択します。すると、コードにTimerのスタブが現れます。



このTickの中に、処理したい内容を書き込みます。
ここでは簡単に、cnt1を加算して、cnt1が10、つまり、10秒たったら、表示しているURLをチェックして、それまでと違ったら、もう一方のものと切り替えるという処理をします。

        private void timer1_Tick(object sender, EventArgs e)
        {
            cnt1++; // cnt1を加算
            if (cnt1 == 10)
            {
                if (url.Equals(url1)) url = url2;
                else url = url1;
                try
                {
                    webBrowser1.Navigate(new Uri(url));
                }
                catch
                {
                }
                cnt1 = 0; // 初期化
            }
        }

さて、これで、10秒おきに、大学のホームページと、Yahoo!のホームページが交互に表示されるようになったはずですが、できましたでしょうか。


ここまでのコード[ダウンロード

(2)シナリオをウェブからとってくる部分のコード追加
次にシナリオをウェブからとってくる部分のコードを追加します。ここでは、httpdサーバーが必要になりますが、今回は、Windowsで簡単に動かせる、AN HTTP Serverを使用したいと思います。httpdサーバーは、リンクを参考に立ち上げておいてください。

(2-1)シナリオファイルフォーマットの決定
今 回はシナリオファイルに書き込んだURLを読み込んで、それを表示するという使用にしたいと思います。XMLファイルを作って、それをパースして、といっ たように作りこんだ方が格好がいいのですが、今回は、簡単にテキストファイルに以下のような内容を書いておくこととします。

1行目:表示するURLの数(整数)
2行目以降:表示したいURL

では、以下のようなファイルをhttpdサーバーのドキュメントルートに保存しておきましょう。名前は、dscenario.txtとしておきましょう。

2
http://www.kait.jp/
http://www.yahoo.co.jp/

(2-2)ファイルの読取部分の追加
それでは、ファイルを読み取る部分を追加します。ファイルの読取は一定の間隔で定期的に行うようにしたいと思います。時間が来たときの処理としては以下を想定します。

(1)所定のシナリオ管理サーバーにアクセスする
(2)読み取ったファイルをローカルディスクに保存する

ローカルディスクとしては、c:\ddsを使用します。フォルダを作成しておいてください。
まず、一定間隔のイベント処理をする部分です。先ほど使用したタイマーとは別のタイマーを追加します。何もしなければTimer2となるはずです。先ほどと同様に、Intervalを1000、EnabledをTrueに変えておきます。



そして、同じく、プロパティのイベントから、Tickをダブルクリックして、スタブを自動生成します。一定間隔の生成ロジックも、先ほどと同じようにしましょう。新しくカウンターとしてcnt2を整数変数として追加します。

        // 変数の定義
        int cnt1 = 0; // 画面切り替えようのカウンター
        int cnt2 = 0; // シナリオファイルのダウンロード用

シ ナリオ管理サーバーへの接続は、30秒おきとします。サーバーへの接続は、WebClientというクラスを使用します。WebClientというクラス のインスタンスを生成し、DownloadFileメソッドを使用して、ファイルをダウンロードします。定期的にアクセスするように、その後、カウンター の値を初期化しておきます。

        private void timer2_Tick(object sender, EventArgs e)
        {
            cnt2++; // カウントアップ
            if (cnt2 == 30) // ファイルダウンロードタイミング
            {
                // シナリオ管理サーバーにアクセスして所定のシナリオファイルをローカルファイルに
                System.Net.WebClient wc = new System.Net.WebClient();
                wc.DownloadFile("http://127.0.0.1/dscenario.txt", @"c:\dds\dscenario.txt");

                // カウンターの初期化
                cnt2 = 0;
            }
        }

さて、ここで実行してみます。空のフォルダーにシナリオファイルが保存されたでしょうか。

(2-2)シナリオ表示部分の追加
で は、いよいよ、シナリオどおりに表示を変更する箇所です。先ほどのコードは、URLが2つと決めうちだったので、今度は、配列を使って、ある程度URLの 数を可変にすることにします。また、変数として、URLの数、また、表示しているウェブの順番を示す整数も新たに定義します。表示の上限は10としておき ます。また、先に作成した、url、url1、url2はもういりません。

        // 変数の定義
        int cnt1 = 0; // 画面切り替えようのカウンター
        int cnt2 = 0; // シナリオファイルのダウンロード用
        string[] url = new string[10]; // URL格納用
        int numAd = 0; // URLの数
        int playAd = 0; // 表示しているウェブの番号

ま ずは、先ほど書き出したファイルを改めて読み出して、URLの数、URLを取り出す部分です。これは、Timer2のTickの中に書き込みます。ファイ ルの書き出しなので、参考文献などを見ても同じように出来ると思います。ここでは、シナリオファイルのURL数と実際のURLの数にずれがないことを前提 としています。読み取ったファイルを全てlinesという配列にいったん格納します。

            cnt2++; // カウントアップ
            if (cnt2 == 30) // ファイルダウンロードタイミング
            {
                // シナリオ管理サーバーにアクセスして所定のシナリオファイルをローカルファイルに
                System.Net.WebClient wc = new System.Net.WebClient();
                wc.DownloadFile("http://127.0.0.1/dscenario.txt", @"c:\dds\dscenario.txt");

                //読み込むテキストファイル
                string textFile = "C:\\dds\\dscenario.txt";
                //文字コード(ここでは、Shift JIS)
                System.Text.Encoding enc = System.Text.Encoding.Default;

                //テキストファイルの中身をすべて読み込む
                //string str = System.IO.File.ReadAllText(textFile, enc);

                //行ごとの配列として、テキストファイルの中身をすべて読み込む
                string[] lines = System.IO.File.ReadAllLines(textFile, enc);

以下、linesから、一行目をURL数として、残りをURLとして取り出す処理を追加します。

                // 一行目をURL数として取り出す
                numAd = int.Parse(lines[0]);
                // 残りの行をURLとして取り出す
                for (int i = 0; i < numAd; i++)
                {
                    url[i] = lines[i + 1];
                }

                // カウンターの初期化
                cnt2 = 0;

これで、URLを取り出せているはずです。

次 に、取り出したURLを表示する部分、つまり、Timer1のTickの書き換えです。先ほどは、時間になったら、URLの中身を直接チェックしていまし たが、それはやめて、表示URLの順序を変えていくようにします。定義したplayAdは初期値が0なので、最初はまず、0番目を表示するようにして、順 番に表示を変えていくようにplayAdをカウントアップします。ただし、URL数の上限に達したら、最初に戻すように、playAdも初期化します。

        private void timer1_Tick(object sender, EventArgs e)
        {
            cnt1++;
            if (cnt1 == 10)
            {
                try
                {
                    webBrowser1.Navigate(new Uri(url[playAd]));
                }
                catch
                {
                }

                // 表示URLをカウントアップ
                playAd++;
                if (playAd >= numAd) playAd = 0; // URL数が上限に達したら初期化

                // 初期化
                cnt1 = 0;
            }
        }

さ て、気づいたと思いますが、このまま動かしてしまうと、url[0]が無くて、エラーになってしまいます。そこで、ここでは、初期画面を追加しておきま す。初期画面は何でも良いのですが、シナリオ管理サーバーに初期画面を作っておきましょう。ここでは、index.htmlという名前のファイルを作成し ました。これをLoadで読み取るようにしておきます。url[0]を表示する変更をするのも忘れないように。

        private void Form1_Load(object sender, EventArgs e)
        {
            url[0] = "http://127.0.0.1/index.html"; // 初期画面
            try
            {
                webBrowser1.Navigate(new Uri(url[0]));
            }
            catch
            {
            }
        }

以上で完成です。動かしてみましょう。無事にURLが切り替わりましたか。URLの数を増やして、実行もして見ましょう。
ここで、気づくのは、最初にシナリオファイルをダウンロードするまで、初期画面が表示されっぱなしだということです。これは、あまりかっこよくありません。ということで、ファイルダウンロードの関数を外だしにし、LoadとTimer2で実行するように変更しておきます。

        private void readFile()
        {
            // シナリオ管理サーバーにアクセスして所定のシナリオファイルをローカルファイルに
            System.Net.WebClient wc = new System.Net.WebClient();
            wc.DownloadFile("http://127.0.0.1/dscenario.txt", @"c:\dds\dscenario.txt");

            //読み込むテキストファイル
            string textFile = "C:\\dds\\dscenario.txt";
            //文字コード(ここでは、Shift JIS)
            System.Text.Encoding enc = System.Text.Encoding.Default;

            //テキストファイルの中身をすべて読み込む
            //string str = System.IO.File.ReadAllText(textFile, enc);

            //行ごとの配列として、テキストファイルの中身をすべて読み込む
            string[] lines = System.IO.File.ReadAllLines(textFile, enc);

            // 一行目をURL数として取り出す
            numAd = int.Parse(lines[0]);
            // 残りの行をURLとして取り出す
            for (int i = 0; i < numAd; i++)
            {
                url[i] = lines[i + 1];
            }
        }

LoadとTimer2で readFile()メソッドを呼び出す。
これで、10秒経過後に、指定のURLが表示されるようになったと思います。

ここまでのコード[ダウンロード
シナリオ管理サーバーファイル[ダウンロード]

(3)アプリケーションの課題
このアプリケーションの課題としては次のようなものがあります。

・サイネージ画面が一般のウェブだけ。
本題とは関係ありませんが、コンテンツ管理サーバーの方も実装する必要があるでしょう。

・サイネージの表示時間
サイネージの表示時間が10秒と固定されているので、これも、URLに応じて変更するなどの工夫ができると思います。

・シナリオファイルのXML化
上記に関連して、XMLをパースして読み出すことができれば、より複雑なシナリオができると思います。

以上のような課題を解決して、より実用的なアプリケーションを作ってみよう。