Skip to content

Instantly share code, notes, and snippets.

@makotoshimazu
Created April 12, 2016 14:31
Show Gist options
  • Save makotoshimazu/8ee10e4a059964c0193786b5f8e8088b to your computer and use it in GitHub Desktop.
Save makotoshimazu/8ee10e4a059964c0193786b5f8e8088b to your computer and use it in GitHub Desktop.
#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