M5StickCとポテンショメータを使ってSlackのステータスを変更するやつ作った


# 背景
この記事を見て、便利そうやし、そこそこ簡単に作れそうやなと思って試してみることにした。
[Slack Status Updater With ESP8266 : 5 Steps (with Pictures) - Instructables](https://www.instructables.com/Slack-Status-Updater-With-ESP8266/)

Slack使い始めはステータス変える気になって使ってたけど、最近はめんどくさくてやってなかった。
これ作ったら、変えるようになるかなと期待してる。

できたのはこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/c7258b2c-b862-fe28-26cc-1a31362df4c9.png)


# 調査
ほぼほぼ、やろうとしてること。真似させていただく。
[M5StackでSlackカスタムステータス変更APIを叩いてステータスを変更してみる | Skyarch Broadcasting](https://www.skyarch.net/blog/?p=18315)

# ハードウェア選定
M5StickCが手元にあったので、それを使った。
[M5StickC - SWITCH-SCIENCE](https://www.switch-science.com/catalog/5517/)

ポテンショメータはこれ使った。ハンダいらず。
[M5Stack用回転角ユニット - SWITCH-SCIENCE](https://www.switch-science.com/catalog/6551/)

# Slack
## アプリ
Slack APIを使うにはSlack上で、まず「アプリ」を作るみたい。
ワークスペースの中にアプリを作る。
[Slack API: Applications | Slack](https://api.slack.com/apps)
権限周りはこんな感じ

![Slack-API-Applications-ACALL-Slack (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/2674d345-df1e-0b57-acda-e976aba6e630.png)

## API
APIはこれらしい。
[users.profile.set method | Slack](https://api.slack.com/methods/users.profile.set)
こんなjsonを投げたら良いみたい。

```json
{
	"status_text": "riding a train",
	"status_emoji": ":mountain_railway:",
}
```

認証はBearer認証ってやつ。シンプル。
[Bearer認証について - Qiita](https://qiita.com/h_tyokinuhata/items/ab8e0337085997be04b1)
[トークンを利用した認証・認可 API を実装するとき Authorization: Bearer ヘッダを使っていいのか調べた - Qiita](https://qiita.com/uasi/items/cfb60588daa18c2ec6f5)


Postmanを使ってためしてみた。
こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/2d8bb2c8-4b2d-329f-1019-fd88833a7a57.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/9b4723b7-9f20-647b-5d91-d3e9689bc033.png)


# M5StickC
## Wi-Fi
シンプル。SSIDとパスワードをWiFi.begin()にわたすだけ。
切れたとき、リトライするみたいな処理も入れたいけど、サボった。

## Angle Sensor
`0 - 4095`で読み込まれる。12bit。

Examplesから選んで試した。
![Screen Shot 2021-04-04 at 21.58.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/7936fa28-c386-642a-84cd-39afa32cc2ed.png)

## jsonをPOST
`serializeJson()`ってのを使ってごにょごにょする。

## メインのところ
enumとかstatic使ってみた。クラス使うともっとスッキリするのかも。Arduino環境でどうしたらよいかよくわからん。ポテンショメータの値を読み取って、適当にしきい値決めて、ステータスに変換してる。ステータスが変更したときだけ、POSTしてる。
.hにバレたら良くない設定系をまとめた。

# コード
こんな感じになった。そこそこ長いけど、やってることはシンプル。

```c++:change_slack_status.ino
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <M5StickC.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include "settings.h"

const int capacity = JSON_OBJECT_SIZE(2);
StaticJsonDocument<capacity> json_request;
char buffer[255];
const char *host = "https://slack.com/api/users.profile.set";

int sensorPin = 33;
enum Status { PRIVATE, WORK, BREAK };

enum Status readStatus(){
  enum Status status;
  int sensorValue = analogRead(sensorPin);
  Serial.println(sensorValue);
  if(0 <= sensorValue && sensorValue <1400){
    status = PRIVATE;
  }else if(1400 <= sensorValue && sensorValue <2800){
    status = WORK;
  }else{
    status = BREAK;
  }
  return status;
}

bool isChanged(enum Status status) {
  static enum Status pre_status;
  bool changed = false;
  if (pre_status != status) {
    changed = true;
  }
  pre_status = status;
  return changed;
}

void sendStatus(enum Status status) {
  HTTPClient http;
  http.begin(host);
  http.addHeader("Content-Type", "application/json");
  http.addHeader("Authorization", token);

  // create JSON
  DynamicJsonDocument doc(1024);
  JsonObject profile = doc.createNestedObject("profile");
  M5.Lcd.setCursor(1, 30);
  M5.Lcd.setTextSize(3);
  M5.Lcd.fillScreen(BLACK);

  switch (status) {
  case PRIVATE:
    profile["status_text"] = "private now";
    profile["status_emoji"] = ":palm_tree:";
    M5.Lcd.printf("PRIVATE");
    break;
  case WORK:
    profile["status_text"] = "work now";
    profile["status_emoji"] = ":office:";
    M5.Lcd.printf("WORK");
    break;
  case BREAK:
    profile["status_text"] = "break now";
    profile["status_emoji"] = ":rice_ball:";
    M5.Lcd.printf("BREAK");
    break;
  }

  profile["status_expiration"] = "0";
  serializeJson(doc, buffer, sizeof(buffer));
  // start connection and send HTTP header
  int status_code = http.POST((uint8_t *)buffer, strlen(buffer));
  Serial.printf("status_code=%d\r\n", status_code);
  if (status_code == 200) {
    Stream *resp = http.getStreamPtr();

    DynamicJsonDocument json_response(255);
    deserializeJson(json_response, *resp);

    serializeJson(json_response, Serial);
    Serial.println("");
  }
  http.end();
}

void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(100);

  Serial.println("start M5 screen");
  M5.begin();
  M5.Axp.ScreenBreath(9);
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(2);
  delay(1000);

  Serial.print("start wifi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }
  Serial.println("");
  M5.Lcd.println("Connected");

  pinMode(sensorPin, INPUT);
}

void loop() {
  enum Status status;
  status = readStatus();
  if (isChanged(status)) {
    sendStatus(status);
  }
  delay(100);
}
```

```h:settings.h
const char *ssid = "hoge";
const char *password = "hoge";
const char *token = "hoge";
```


# できあがり
こんな感じになった。いい感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/c7258b2c-b862-fe28-26cc-1a31362df4c9.png)

# おわりに
いい感じの作れて満足。
期待通り、動いてる。