プログラマーは怠惰の人たち
プログラマーは怠惰の人たちだという説がある。なぜならというと、2回以上繰り返す可能性のある物事に対して、ついスクリプトなどを書いてしまうからだ。たとえ1回ごとに数秒で済むことであろう、2時間以上かかってプログラミングすることはよくある。今回のこのつまらないものでも、これに似る思考から生み出されたものだ。
解決すべく課題
一言というと、毎日のPC起動がしんどいだ。きれいさっぱりに収まるために、自作PCが結構ユニークなケースを採用した。それで毎回デスクの下へ探って電源オンにしなければならない。これを解消すべき、何とかして電源スイッチをデスクトップに移したい。
参考にデスクトップ環境の写真を添付する
ESP32に至る経緯
一番シンプルな解決策
単純にマザーボードへもう一つの電源ジャンパーを接続させて、適当にスイッチを設置すれば済む話ですが、そうするとあまり面白味がなくて変にケーブルが繋いて格好悪いからやめた。
キーボードによる起動
電源オフ状態から起動させるには、PS/2端子のキーボードでないといけない。USBで起動できるのは、せいぜいスリープ状態ぐらいのパソコンだ。
電源状態
ACPI ( Advanced Configuration and Power Interface ) は 電源管理の規格で、S0 ~ S5 までのスリープ状態が規定されている。
コード | 状態 | 起動可能の方式 |
---|---|---|
S0 | 通常の運用状態 | - |
S1 | スタンバイ | USB、PCIe、ソフトウェア |
S2 | サスペンド | USB、PCIe、ソフトウェア |
S3 | スリープ | USB、PCIe、ソフトウェア |
S4 | 休止・ハイバネーション(ハイブリットシャットダウン) | PS/2、PCIe |
S5 | 電源断 | PS/2、PCIe |
WOL
「Wake On LAN」とは、「マジックパケット」と呼ばれるネットワークパケットを送信することで、PCをスリープ状態から「復帰(Wake)」させる機能だ。
電源オフ(S5)の状態でも、PCIeからの起動ができるため、マザーボードに有線LANが接続されている限り、WOLを使ってPCを起動させるのは現実的だと思う。ちょうど研修で使っていたESP32は最近使ってないので、今度はそれを使ってワイヤレスの電源スイッチを作ろうと思う。
準備
ハードウェア
ソフトウェア
- ESP32のWOLライブラリー
https://github.com/a7md0/WakeOnLan - マザーボードのWOL有効化
- 念のためネットインタフェースの設定も
接続
いざコーディング
#include <WiFi.h>
#include <WiFiUdp.h>
#include <WakeOnLan.h>
// スイッチ
#define PIN_SW1 5
// WIFI設定
WiFiUDP UDP;
WakeOnLan WOL(UDP);
const char* ssid = "your-ssid";
const char* password = "your-password";
// マジックパッケージ送信
void wakeMyPC() {
const char *MACAddress = "01:23:45:67:89:AB";
WOL.sendMagicPacket(MACAddress);
}
// チャタリングフリー・スリーブ復帰
unsigned long lastTimeSW1 = 0;
bool sw1 = false;
void IRAM_ATTR handleSW1()
{
unsigned long now = millis();
if ( (now - lastTimeSW1) > 200 ) sw1 = !sw1;
lastTimeSW1 = now;
}
setup() {
// ピンモード初期化
pinMode(PIN_SW1, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PIN_SW1), handleSW1, FALLING);
// Wi-Fiに接続
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println(WiFi.localIP());
}
loop() {
if (sw1) {
// マジックパケットを送信する
Serial.println("電源ON");
wakeMyPC();
delay(500);
}
//スリープ節電
esp_deep_sleep_start();
}