ズルいIoTでリモハラ対策してストレスフリーになろう！

# オッス！オラ在宅

　リモワしているとポモドーロ・テクニックみたいなちょっとした息抜きをし辛くないですか？もしくは家族の容赦ない割り込みと上司の定める離席ルールって相容れないですよね。

#### 席に座ってるのが見えてれば良い？それ、IoTでなんとかできます。

# いっちょやってみっか！

材料です。

 - ESP32とかArduino系マイコン
 - HC-SR04など距離測定デバイス
 - Webカメラなど自分の仕事姿を撮影できるデバイス
 - 動画を再生するディスプレイ

# ワクワクすっぞ！

**一定時間離席すると自動でキー入力してくれる仮想キーボードデバイスです**

![shigoto_man_casual.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189193/2fd4040c-ee0e-632f-e5b9-3374254d435b.png)

　最初にWebカメラで仕事してる動画を撮影してください。改行キーでループ再生するように設定してください。

　コードをESP32に書き込んで距離センシングを組み立てます

![esp32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189193/a51cb590-ab9e-1f7d-48a7-bf6eb6c7594b.png)

　デバイスをBluetoothでペアリングします。

![pairing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189193/cee961ec-9980-44a3-3ce1-77ad5efbf72b.png)

　上司がこちらを見てない隙に仕事中動画にWebカメラをセットします。~~なあにポテチ袋に液晶テレビ仕込むより簡単ですよ！~~

　離席しましょう。5秒カウントすると動画が再生されます。

![term.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189193/677d8baa-de90-63a3-a43c-a9f651ea6b83.png)

　上司に「全力コーディング集中します。反応が遅いかもしれません。」とでもメッセージを入れてあげるとなお効果的でしょう。ｗ

# コード
<details><summary>zuruiot.ino</summary><div>

```
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include "BLE2902.h"
#include "BLEHIDDevice.h"
#include "HIDTypes.h"
#include "HIDKeyboardTypes.h"

BLEHIDDevice* hid;
BLECharacteristic* input;
BLECharacteristic* output;

uint8_t buttons = 0;
uint8_t button1 = 0;
uint8_t button2 = 0;
uint8_t button3 = 0;
bool connected = false;

#define Trigger_Pin 17
#define Echo_Pin 16
int V = 340; //音速

int dest = 50; //何センチ以下でカウンターを下げるか
boolean enterFlag = false; //在席・離席フラグ
int enterCounter = 5; // 何回閾値以下になったら改行を押すか

class MyCallbacks : public BLEServerCallbacks {
	void onConnect(BLEServer* pServer){
		connected = true;
		BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
		desc->setNotifications(true);
	}

	void onDisconnect(BLEServer* pServer) {
		connected = false;
		BLE2902* desc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
		desc->setNotifications(false);
	}
};

class MyOutputCallbacks : public BLECharacteristicCallbacks {
	void onWrite(BLECharacteristic* me){
		uint8_t* value = (uint8_t*)(me->getValue().c_str());
		ESP_LOGI(LOG_TAG, "special keys: %d", *value);
	}
};

void taskServer(void*){
	BLEDevice::init("ZuruIoT");
	BLEServer *pServer = BLEDevice::createServer();
	pServer->setCallbacks(new MyCallbacks());

	hid = new BLEHIDDevice(pServer);
	input = hid->inputReport(1); // <-- input REPORTID from report map
	output = hid->outputReport(1); // <-- output REPORTID from report map

	output->setCallbacks(new MyOutputCallbacks());

	std::string name = "ElectronicCats";
	hid->manufacturer()->setValue(name);

	hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
	hid->hidInfo(0x00,0x02);

	BLESecurity *pSecurity = new BLESecurity();
	//pSecurity->setKeySize();
	pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);

	const uint8_t report[] = {
		USAGE_PAGE(1),	  0x01,	   // Generic Desktop Ctrls
		USAGE(1),		   0x06,	   // Keyboard
		COLLECTION(1),	  0x01,	   // Application
		REPORT_ID(1),	   0x01,		//   Report ID (1)
		USAGE_PAGE(1),	  0x07,	   //   Kbrd/Keypad
		USAGE_MINIMUM(1),   0xE0,
		USAGE_MAXIMUM(1),   0xE7,
		LOGICAL_MINIMUM(1), 0x00,
		LOGICAL_MAXIMUM(1), 0x01,
		REPORT_SIZE(1),	 0x01,	   //   1 byte (Modifier)
		REPORT_COUNT(1),	0x08,
		HIDINPUT(1),		   0x02,	   //   Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position
		REPORT_COUNT(1),	0x01,	   //   1 byte (Reserved)
		REPORT_SIZE(1),	 0x08,
		HIDINPUT(1),		   0x01,	   //   Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
		REPORT_COUNT(1),	0x06,	   //   6 bytes (Keys)
		REPORT_SIZE(1),	 0x08,
		LOGICAL_MINIMUM(1), 0x00,
		LOGICAL_MAXIMUM(1), 0x65,	   //   101 keys
		USAGE_MINIMUM(1),   0x00,
		USAGE_MAXIMUM(1),   0x65,
		HIDINPUT(1),		   0x00,	   //   Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position
		REPORT_COUNT(1),	0x05,	   //   5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
		REPORT_SIZE(1),	 0x01,
		USAGE_PAGE(1),	  0x08,	   //   LEDs
		USAGE_MINIMUM(1),   0x01,	   //   Num Lock
		USAGE_MAXIMUM(1),   0x05,	   //   Kana
		HIDOUTPUT(1),		  0x02,	   //   Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
		REPORT_COUNT(1),	0x01,	   //   3 bits (Padding)
		REPORT_SIZE(1),	 0x03,
		HIDOUTPUT(1),		  0x01,	   //   Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile
		END_COLLECTION(0)
	};

	hid->reportMap((uint8_t*)report, sizeof(report));
	hid->startServices();

	BLEAdvertising *pAdvertising = pServer->getAdvertising();
	pAdvertising->setAppearance(HID_KEYBOARD);
	pAdvertising->addServiceUUID(hid->hidService()->getUUID());
	pAdvertising->start();
	hid->setBatteryLevel(7);

	ESP_LOGD(LOG_TAG, "Advertising started!");
	delay(portMAX_DELAY);
  
};

void setup() {
	Serial.begin(115200);
	pinMode(Trigger_Pin, OUTPUT);
	pinMode(Echo_Pin, INPUT);
	digitalWrite(Trigger_Pin, LOW);
	xTaskCreate(taskServer, "server", 20000, NULL, 5, NULL);
}

void sendTrigger() {
  digitalWrite(Trigger_Pin,HIGH);
  delayMicroseconds(10);
  digitalWrite(Trigger_Pin, LOW);
}

void enterPress() {
	vTaskDelay(1000);
	const char* hello = "\n";
	while(*hello) {
		KEYMAP map = keymap[(uint8_t)*hello];
		Serial.println(buttons);
		uint8_t msg[] = {map.modifier || buttons, 0x0, map.usage, 0x0,0x0,0x0,0x0,0x0};
		input->setValue(msg,sizeof(msg));
		input->notify();
		hello++;
		uint8_t msg1[] = {0x0, 0x0, 0x0, 0x0,0x0,0x0,0x0,0x0};
		input->setValue(msg1,sizeof(msg1));
		input->notify();
		delay(10);
	}
	xTaskCreate(taskServer, "server", 20000, NULL, 5, NULL);
}

void loop() {
	sendTrigger();
	while(!digitalRead(Echo_Pin)){ }
	unsigned long t1 = micros();

	while(digitalRead(Echo_Pin)){ }
	unsigned long t2 = micros();
	unsigned long t = t2 - t1;
	int dis = V * t /20000;
	Serial.print(dis);
	Serial.println("cm");
	
	if (enterFlag == false) {
		if (dis > dest) {
		  	enterCounter--;
			Serial.println("RISEKI!");
			Serial.println(enterCounter);
			if (enterCounter < 0) {
				enterPress();
				enterCounter = 5;
				enterFlag = true;
			}
		} else {
			enterCounter = 5;
		}
	} else {
		if (dis < dest) {
		  	enterCounter--;
			Serial.println("ZAISEKI!");
			Serial.println(enterCounter);
			if (enterCounter < 0) {
				enterPress();
				enterCounter = 5;
				enterFlag = false;
			}
		} else {
			enterCounter = 5;
		}
	}
	delay(1000);
}
```
</div></details>

# もうちょっとだけ続くんじゃ

え！？
離席検出がデプスカメラ対応だって！？そんなあ・・・

ま、3時間くらいで作ったジョークプログラムってことで！！ｗ

# FYI

 - 距離センサーの使い方の参考に

[ESP32 HC-SR04による距離の測定](https://blog.goo.ne.jp/jh7ubc/e/67f69aaf54de405756b03ffbbcb8d183)

 - BLEキーボードの実装の参考に

[ElectronicCats / Backpacks_Meow](https://github.com/ElectronicCats/Backpacks_Meow)