M5StickC をguest Wifi のパスワード表示機にする
お客さんにguest用のWifiのパスワードを表示する方法を考えた。
要件
- 日毎に変更するパスワードを表示するために、ディスプレイが必要
- 会議室の反対側にいる人にも見えるように、壁掛けならA4くらい大きさが必要
- パスワードはアルファベット大文字・小文字と数字8桁
- パスワードは某サーバの認証付きWebサーバ上にある
問題は、離せばわかるお年頃の方にも問題なく見えるようにすること。
最初はMatrix LEDの64x16くらいの大きさを考えていた。
しかし、パスワードが電光掲示板に常に表示されているなんて、かっこ悪い。
ということで、数時間なら電源接続がいらず、手元に参照でき、フォントもわかりやすい26pixelカーニングフォントが使える、M5StickCを利用することにした。
処理概要
初期化
既存のWifi AccessPoint に接続する。
接続には意外と時間がかかるため、接続するたびに32x500msec=16sec の接続成功待ちをする。500msec毎に .
を表示。
#include <WiFi.h>
const char* _ssid = "接続するAPのSSID";
const char* _password = "接続APのパスワード";
wifi_setup() {
WiFi.begin(_ssid, _password);
int count = 32; // 32 * 500msec = 16sec
while (WiFi.status() != WL_CONNECTED) {
delay(500);
M5.Lcd.print(".");
count -= 1;
if (count == 0) {
M5.Lcd.setTextSize(1);
M5.Lcd.setTextFont(2);
M5.Lcd.setTextColor(RED);
M5.Lcd.println("fail wifi connect");
delay(500);
return -1;
}
}
2回の待ちも失敗すると、エラー表示する。
接続成功後は、取得したIPアドレスなどが以下のようにわかる。
M5.Lcd.println("");
M5.Lcd.println("WiFi connected.");
M5.Lcd.print("IP address: ");
M5.Lcd.println(WiFi.localIP());
M5.Lcd.println();
delay(1000);
}
guest Wifi 表示
フォントと色は以下のサイトで探した。
今回は、1: Adafruit 8ピクセルASCIIフォント
と 2: 16ピクセルASCIIフォント
と、 4: 26ピクセルASCIIフォント
を利用した。
SSID:
などタイトルは、16px。- 値は、26px。
- 時刻表示は、8px。
SSIDなどはこんな感じで表示。
- M5.Lcd.fillScreen(色) ... 画面全体を塗りつぶし
- M5.Lcd.setTextFonr(フォントの種類)
- M5.Lcd.setTextSize(フォントの倍角数) ... 1で1倍。2で2倍。
- M5.Lcd.setCursor(x, y)
- M5.Lcd.setTextColor(色)
// display values on LCD
M5.Lcd.setTextSize(1);
M5.Lcd.setTextFont(4);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 0);
M5.Lcd.setTextFont(2);
M5.Lcd.setTextColor(DARKGREY);
M5.Lcd.printf("SSID: ");
M5.Lcd.setCursor(36, 0);
M5.Lcd.setTextFont(4);
M5.Lcd.setTextColor(DARKGREEN);
M5.Lcd.printf("%s\r\n", _display_ssid);
M5.Lcd.setCursor(0, 24);
M5.Lcd.setTextFont(2);
M5.Lcd.setTextColor(DARKGREY);
M5.Lcd.printf("USER: ");
M5.Lcd.setTextFont(4);
M5.Lcd.setCursor(36, 20);
M5.Lcd.setTextColor(DARKGREEN);
M5.Lcd.printf("guest\r\n");
M5.Lcd.setCursor(0, 48);
M5.Lcd.setTextFont(2);
M5.Lcd.setTextColor(DARKGREY);
M5.Lcd.printf("PWD: ");
M5.Lcd.setCursor(36, 48);
M5.Lcd.setTextFont(4);
M5.Lcd.setTextColor(DARKGREEN);
M5.Lcd.printf(passwd);
時刻表示
電源投入時、M5StickCの時計は、当然狂っている。
ntp serverに時間をとりにいって、時間を合わせる。
#include <WiFi.h>
#include "time.h"
//
// setup RTC by NTP
//
void setup_rtc() {
struct tm timeinfo;
uint8_t hh, mm, ss;
RTC_TimeTypeDef TimeStruct;
// connect NTP server
configTime(9 * 3600, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
if (!getLocalTime(&timeinfo)) {
M5.Lcd.println("Failed to obtain time");
return;
}
//
// set localtime to RTC
//
hh = timeinfo.tm_hour;
mm = timeinfo.tm_min;
ss = timeinfo.tm_sec;
TimeStruct.Hours = hh;
TimeStruct.Minutes = mm;
TimeStruct.Seconds = ss;
M5.Rtc.SetTime(&TimeStruct);
}
時刻表示はこんな感じ。
あまり頻繁に書き換えたくないので、static変数 _RTC_TimeStruct
で前回の時刻取得内容を保持し、秒が変更されたときだけ、画面を書き換える。
void display_time() {
static RTC_TimeTypeDef _RTC_TimeStruct;
RTC_TimeTypeDef RTC_TimeStruct;
// get time
M5.Rtc.GetTime(&RTC_TimeStruct);
if (RTC_TimeStruct.Seconds != _RTC_TimeStruct.Seconds) {
// display time
M5.Lcd.setTextSize(1);
M5.Lcd.setTextFont(1);
M5.Lcd.setCursor(32, 9*8);
M5.Lcd.setTextColor(DARKGREEN);
M5.Lcd.fillRect(40, 9*8, 256, 12, BLACK);
M5.Lcd.printf("Time: %02d : %02d : %02d\n",
RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
}
memcpy(&_RTC_TimeStruct, &RTC_TimeStruct, sizeof(RTC_TimeStruct));
}
電源管理
起動して、guest Wifi用のパスワードを表示した後、どうするか?
そのまま表示しつづけると、2つの問題がある
- 翌日になればパスワードは変更される
- 大抵は操作後、1分も表示できれば十分。その後は消してもいい。
ということで、以下の処理を loop()
に記述した。
- 100秒ほどで画面を暗くして、バッテリを節約
Button A
を押すとリセット(Wifi 再接続&パスワード再取得)Button B
を押すと画面を100秒ほど明るくする
#define BRIGHT_TIME 1000
int16_t _countdown = BRIGHT_TIME; // 1000 * 100sec = 100sec
void loop() {
// pinの状態など更新
M5.update();
// for reset
if (M5.BtnA.wasPressed() == 1) {
esp_restart();
}
if (M5.BtnB.wasPressed() == 1) {
_countdown = BRIGHT_TIME;
M5.Axp.ScreenBreath(10);
}
if (_countdown < 0) {
// dark screen for battery
M5.Axp.ScreenBreath(7);
} else {
display_time();
--_countdown;
}
delay(100);
}