Skip to content

Instantly share code, notes, and snippets.

@NaotoKumagai
Last active February 26, 2021 02:08
Show Gist options
  • Save NaotoKumagai/263cb73d7c7d6eb7680abf61c0cbfc04 to your computer and use it in GitHub Desktop.
Save NaotoKumagai/263cb73d7c7d6eb7680abf61c0cbfc04 to your computer and use it in GitHub Desktop.
シェアハウスのお風呂利用状況監視君
#include <Arduino.h>
#include <Hash.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#include <WebSocketsClient.h>
#include <ArduinoJson.h>
extern "C" {
#include "user_interface.h"
}
#define WIFI_SSID "接続したいSSID"
#define WIFI_PWD "SSIDのパスワード"
#define SLACK_SSL_FINGERPRINT "AB F0 5B A9 1A E0 AE 5F CE 32 2E 7C 66 67 49 EC DD 6D 6A 38"
#define SLACK_BOT_TOKEN "SlackBotのトークン"
#define SLACK_DEFAULT_CHANNEL "投稿するデフォルトのチャンネル" //この辺りどうするかは運用に合わせて
#define SLACK_BOT_USER_ID "BOTのUserID" //自分の投稿を読み取らない様にハードコードで回避(rtm.startから取得したほうがカッコイイかも)
#define HTML_HEADER "<!doctype html>"\
"<html><head><meta charset=\"UTF-8\"/>"\
"<meta name=\"viewport\" content=\"width=device-width\"/>"\
"</head><body>"
#define HTML_FOOTER "</body></html>"
bool connected = false;
bool helloSaid = false;
unsigned long lastAccess =0;
WebSocketsClient webSocket;
ESP8266WebServer server(80);
// 光センサの値取得
int getToutValue() {
int res = system_adc_read(); // アナログ値の読み取り
return res;
}
String getToutString() {
if (getToutValue() < 150) { //手持ちのセンサではしきい値150位で良い塩梅だった。
return "お風呂空いてます";
}
return "お風呂利用中です";
}
String getImageHTML() {
if (getToutValue() < 150) {
return "<br><img src=\"http://01.gatag.net/img/201506/11l/gatag-00006874.jpg\"><br>";
}
return "<br><img src=\"http://01.gatag.net/img/201507/12l/gatag-00010490.jpg\"><br>";
}
// グローバルIPの取得(外から利用する予定は無いけどなんとなく)
String findPublicIP() {
WiFiClient client;
if (client.connect("api.ipify.org", 80)) {
client.println("GET /?format=txt HTTP/1.0");
client.println("Host: api.ipify.org");
client.println();
} else {
Serial.println("connection failed");
}
delay(50);
int a = 1;
while (client.connected()) {
a = a + 1;
String line = client.readStringUntil('\n');
if (a == 10) {
Serial.println(line);
return line;
}
}
return "";
}
void sendPing() {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["type"] = "ping";
String json;
root.printTo(json);
webSocket.sendTXT(json);
}
bool connectToSlack() {
HTTPClient http;
http.begin("https://slack.com/api/rtm.start?token=" SLACK_BOT_TOKEN, SLACK_SSL_FINGERPRINT);
int httpCode = http.GET();
if (httpCode != HTTP_CODE_OK) {
Serial.printf("HTTP GET failed with code %d\n", httpCode);
return false;
}
WiFiClient *client = http.getStreamPtr();
client->find("wss:\\/\\/");
String host = client->readStringUntil('\\');
String path = client->readStringUntil('"');
path.replace("\\/", "/");
Serial.println("WebSocket Host=" + host + " Path=" + path);
webSocket.beginSSL(host, 443, path, "", "");
webSocket.onEvent(webSocketEvent);
return true;
}
void webSocketEvent(WStype_t type, uint8_t *payload, size_t len) {
switch (type) {
case WStype_DISCONNECTED:
Serial.printf("[WebSocket] Disconnected :-( \n");
connected = false;
break;
case WStype_CONNECTED:
Serial.printf("[WebSocket] Connected to: %s\n", payload);
break;
case WStype_TEXT:
Serial.printf("[WebSocket] Message: %s\n", payload);
processSlackMessage((char*)payload);
break;
}
}
void processSlackMessage(char *payload) {
StaticJsonBuffer<1000> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(payload);
if (!root.success()) {
Serial.println("[Json] Parse failed");
return;
}
if (root.containsKey("type")) {
if (strcmp("hello", root["type"]) == 0) {
helloSaid = true;
} else if (strcmp("message", root["type"]) == 0 ) {
if (!root.containsKey("user") || strcmp(SLACK_BOT_USER_ID, root["user"]) != 0) {
if (root.containsKey("text")) {
if (((String)(root["text"].asString())).substring(0, 12) == "<@" SLACK_BOT_USER_ID ">") {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["type"] = "message";
root["channel"] = SLACK_DEFAULT_CHANNEL;
root["text"] = getToutString() + ":bathtub:";
sendMessage(root);
}
}
}
}
}
}
void sendMessage() {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["type"] = "message";
root["channel"] = SLACK_DEFAULT_CHANNEL;
root["text"] = "hoge";
String json;
root.printTo(json);
webSocket.sendTXT(json);
}
void sendMessage(JsonObject& root) {
String json;
root.printTo(json);
webSocket.sendTXT(json);
}
void setupWebServer() {
server.on("/", []() {
lastAccess = millis();
String html = HTML_HEADER "<h1>" + getToutString() + "</h1>" + getImageHTML() + HTML_FOOTER;
server.send(200, "text/html", html);
});
server.on("/sensor", []() {
String accessSec = String((millis() - lastAccess)/1000);
String html = HTML_HEADER;
html+="<h1> 光センサの値 : ";
html+=getToutValue();
html+="</h1><br><h1>最後のアクセスから";
html+=accessSec;
html+="sec</h1>";
html+= HTML_FOOTER;
server.send(200, "text/html", html);
});
server.begin();
}
unsigned long lastPing = 0;
void slackBotLoop() {
webSocket.loop();
if (connected) {
if (millis() - lastPing > 5000) {
if (helloSaid) {
sendPing();
}
lastPing = millis();
}
} else {
connected = connectToSlack();
lastPing = millis();
}
}
void setup() {
Serial.begin(9600);
Serial.setDebugOutput(true);
WiFi.begin(WIFI_SSID, WIFI_PWD);
Serial.println("");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("Grobal IP = " + findPublicIP());
Serial.println("Local IP = " + WiFi.localIP());
setupWebServer();
}
void loop() {
server.handleClient();
slackBotLoop();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment