Created
April 12, 2016 14:31
-
-
Save makotoshimazu/8ee10e4a059964c0193786b5f8e8088b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ESP8266WiFi.h> | |
#include <WiFiClient.h> | |
#include <Stewitter.h> | |
/* Settings */ | |
const int irLedPin = 4; | |
const char* ssid = "ssid"; | |
const char* password = "password"; | |
Stewitter<WiFiClient> twitter("your_token"); | |
const char * const VALID_USERS[] = { | |
"MakotoShimazu", | |
}; | |
/*** Codes ***/ | |
/* IR */ | |
void irled_init() { | |
pinMode(irLedPin, OUTPUT); | |
} | |
const int halfOf38kHz = 13; /* 26.13us / 2 =: 13 us */ | |
void irled_on(uint64 us) { | |
uint64 prev_us = micros(); | |
do { | |
digitalWrite(irLedPin, HIGH); | |
delayMicroseconds(halfOf38kHz); | |
digitalWrite(irLedPin, LOW); | |
delayMicroseconds(halfOf38kHz); | |
} while(micros() - prev_us < us); | |
} | |
void irled_off(uint64 us) { | |
uint64 prev_us = micros(); | |
digitalWrite(irLedPin, LOW); | |
while(micros() - prev_us < us); | |
} | |
const uint64 high_us = 440; | |
const uint64 zero_low_us = 416; | |
const uint64 one_low_us = 1280; | |
const uint64 leader_high_us = 3450; | |
const uint64 leader_low_us = 1710; | |
class Command { | |
public: | |
enum Mode { | |
WARMER = 0x08, | |
COOLER = 0x18, | |
DEHUMID = 0x10, | |
}; | |
enum TimerMode { | |
TIM_NONE = 0x00, | |
TIM_ON = 0x05, | |
TIM_OFF = 0x03 | |
}; | |
enum WindPower { | |
POW_AUTO = 0, | |
POW_WEAK = 1, | |
POW_NORMAL = 2, | |
POW_STRONG = 3 | |
}; | |
enum WindDirection { | |
DIR_VALUE = 0, | |
DIR_SWING = 0x78, | |
DIR_AUTO = 0x80 | |
}; | |
Command(bool power, Mode mode, int temp) : | |
power_(power), mode_(mode), temp_(temp), timer_mode_(TIM_NONE), | |
wind_power_(POW_AUTO), wind_direction_(DIR_AUTO) {}; | |
void send() { | |
uint8 commandbuf[18]; | |
copyToBuffer(commandbuf, 18); | |
out_leader(); | |
out_bytes(commandbuf, 18); | |
out_bit(0); | |
delay(10); | |
}; | |
private: | |
void out_leader() { | |
irled_on(leader_high_us); | |
irled_off(leader_low_us); | |
} | |
void out_bit(uint8 one_bit) { | |
irled_on(high_us); | |
irled_off((one_bit) ? one_low_us : zero_low_us); | |
} | |
void out_byte(uint8 one_byte) { | |
for (int i = 0; i < 8; i++) { | |
out_bit(one_byte & 1); | |
one_byte >>= 1; | |
} | |
} | |
void out_bytes(uint8 *bytes, int length) { | |
for (int i = 0; i < length; i++) | |
out_byte(bytes[i]); | |
} | |
int copyToBuffer(uint8 *buf, int len) { | |
if (len < 18) | |
return -1; | |
buf[0] = 0x23; | |
buf[1] = 0xCB; | |
buf[2] = 0x26; | |
buf[3] = 0x01; | |
buf[4] = 0x00; | |
buf[5] = (power_) ? 0x20 : 0x00; | |
buf[6] = mode_; | |
buf[7] = temp_ - 16; /* 温度 (16度が0) */ | |
buf[8] = 0x30; /* 除湿の強さ */ | |
buf[9] = 0x80; /* 風向風量の自動が0x80 */ | |
buf[10] = 0x00; | |
buf[11] = (timer_mode_ == TIM_OFF) ? timer_minutes_ / 10 : 0; | |
buf[12] = (timer_mode_ == TIM_ON) ? timer_minutes_ / 10 : 0; | |
buf[13] = timer_mode_; | |
buf[14] = 0x00; | |
buf[15] = 0x00; | |
buf[16] = 0x00; | |
int sum = 0; | |
for (int i = 0; i < 17; i++) | |
sum += buf[i]; | |
buf[17] = sum & 0xFF; | |
return 18; | |
} | |
bool power_; | |
Mode mode_; | |
int temp_; | |
TimerMode timer_mode_; | |
int timer_minutes_; | |
WindPower wind_power_; | |
WindDirection wind_direction_; | |
int wind_direction_value_; /* 0x48 - 0x60 0x08きざみで4段階 */ | |
}; | |
String parseDate(const String &mention) { | |
/* format: "date | message ID | screenName | message" */ | |
uint32 from, to; | |
from = mention.indexOf("|"); | |
to = mention.indexOf("|", from + 1); | |
return mention.substring(from + 1, to); | |
} | |
String parseScreenName(const String &mention) { | |
/* format: "date | message ID | screenName | message" */ | |
uint32 from, to; | |
from = mention.indexOf("|"); | |
from = mention.indexOf("|", from + 1); | |
to = mention.indexOf("|", from + 1); | |
return mention.substring(from + 1, to); | |
} | |
String parseMessage(const String &mention) { | |
/* format: "date | message ID | screenName | message" */ | |
uint32 from; | |
from = mention.indexOf("|"); | |
from = mention.indexOf("|", from + 1); | |
from = mention.indexOf("|", from + 1); | |
String message = mention.substring(from + 1); | |
message.trim(); | |
return message; | |
} | |
String truncateUserAts(const String &message) { | |
uint32 from = 0; | |
while (message.substring(from).startsWith("@")) { | |
from = message.indexOf(" ", from + 1) + 1; | |
if (from >= message.length()) | |
return String(""); | |
} | |
return message.substring(from); | |
} | |
bool isValidUser(const String &screen_name) { | |
for (uint i = 0; i < sizeof(VALID_USERS) / sizeof(char *); i++) { | |
if (screen_name.equals(VALID_USERS[i])) | |
return true; | |
} | |
return false; | |
} | |
enum CommandID { | |
COMMAND_ON = 0, | |
COMMAND_OFF, | |
COMMAND_FAIL = -1, | |
}; | |
CommandID fetchCommandFromLastMention() { | |
static String latest_date; | |
Serial.println("connecting ..."); | |
if (!twitter.lastMention()) { | |
Serial.println("connection failed."); | |
return COMMAND_FAIL; | |
} | |
int status = twitter.wait(); | |
if (status != 200) { | |
Serial.print("failed : code "); | |
Serial.println(status); | |
return COMMAND_FAIL; | |
} | |
String mention = twitter.response(); | |
Serial.print("Mention: "); | |
Serial.println(mention); | |
String date = parseDate(mention); | |
String screen_name = parseScreenName(mention); | |
String message = truncateUserAts(parseMessage(mention)); | |
/* Check if mention is updated */ | |
if (date == latest_date) { | |
Serial.println("No update"); | |
return COMMAND_FAIL; | |
} | |
latest_date = date; | |
/* Debug prints */ | |
Serial.print("User: "); | |
Serial.print(screen_name); | |
Serial.print(" Message: "); | |
Serial.print(parseMessage(mention)); | |
Serial.print(" RemoveAts: "); | |
Serial.print(message); | |
Serial.println(""); | |
if (!isValidUser(screen_name)) { | |
Serial.print("Invalid User: "); | |
Serial.print(screen_name); | |
Serial.println(""); | |
return COMMAND_FAIL; | |
} | |
/* Parse the message */ | |
if (message.startsWith("ON")) | |
return COMMAND_ON; | |
if (message.startsWith("OFF")) | |
return COMMAND_OFF; | |
return COMMAND_FAIL; | |
} | |
void setup() | |
{ | |
Serial.begin(115200); | |
irled_init(); | |
pinMode(13, OUTPUT); | |
digitalWrite(13, LOW); | |
WiFi.begin(ssid, password); | |
Serial.println(""); | |
// Wait for connection | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(""); | |
Serial.print("Connected to "); | |
Serial.println(ssid); | |
Serial.print("IP address: "); | |
Serial.println(WiFi.localIP()); | |
for (int i = 0; i < 2; i++) { | |
digitalWrite(13, HIGH); | |
delay(500); | |
digitalWrite(13, LOW); | |
delay(500); | |
} | |
} | |
void loop() | |
{ | |
CommandID id = fetchCommandFromLastMention(); | |
if (id == COMMAND_ON) { | |
Serial.println("ON!"); | |
digitalWrite(13, HIGH); | |
Command command(true, Command::WARMER, 23); | |
command.send(); | |
command.send(); | |
} else if (id == COMMAND_OFF) { | |
Serial.println("OFF!"); | |
digitalWrite(13, LOW); | |
Command command(false, Command::WARMER, 23); | |
command.send(); | |
command.send(); | |
} else if (id == COMMAND_FAIL) { | |
Serial.println("FAILURE..."); | |
} else { | |
Serial.println("Unknown state!"); | |
} | |
delay(20 * 1000); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment