├── .vscode ├── settings.json ├── arduino.json └── c_cpp_properties.json └── FujitsuWebServer.ino /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.errorSquiggles": "Disabled" 3 | } -------------------------------------------------------------------------------- /.vscode/arduino.json: -------------------------------------------------------------------------------- 1 | { 2 | "board": "esp8266:esp8266:nodemcuv2", 3 | "configuration": "CpuFrequency=80,UploadSpeed=115200,FlashSize=4M3M", 4 | "port": "/dev/cu.SLAB_USBtoUART", 5 | "sketch": "FujitsuWebServer.ino" 6 | } -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "/Users/fcoury/Documents/Arduino/libraries/SimpleDHT", 7 | "/Users/fcoury/Documents/Arduino/libraries/IRremoteESP8266/src", 8 | "/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/", 9 | "/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/EEPROM/", 10 | "/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/SPI/", 11 | "/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/SoftwareSerial/", 12 | "/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/Wire/", 13 | "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/avr/include/", 14 | "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/avr/include/avr/", 15 | "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/avr/include/compat/", 16 | "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/avr/include/util/", 17 | "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/lib/gcc/avr/4.*.*/include/", 18 | "/Applications/Arduino.app/Contents/Java/hardware/tools/avr/lib/gcc/avr/4.*.*/include-fixed/", 19 | "/Applications/Arduino.app/Contents/Java/libraries/WiFi/src", 20 | "/Applications/Arduino.app/Contents/Java/libraries/", 21 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266AVRISP/src", 22 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266HTTPClient/src", 23 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266httpUpdate/src", 24 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266HTTPUpdateServer/src", 25 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266mDNS", 26 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266SSDP", 27 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266WebServer/src", 28 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266WiFi/src", 29 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/libraries/ESP8266WiFiMesh/src", 30 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/cores/esp8266", 31 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/tools/sdk/include", 32 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/variants/ESPDuino/", 33 | "/Users/fcoury/Library/Arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2/xtensa-lx106-elf/", 34 | "/Users/fcoury/Library/Arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/lib/gcc/xtensa-lx106-elf/4.8.2/include", 35 | "/Users/fcoury/Library/Arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/xtensa-lx106-elf/include/c++/4.8.2" 36 | ], 37 | "browse": { 38 | "limitSymbolsToIncludedHeaders": false, 39 | "path": [ 40 | "/Users/fcoury/Library/Arduino15/packages/esp8266/hardware/esp8266/2.3.0/cores/esp8266" 41 | ] 42 | }, 43 | "intelliSenseMode": "clang-x64", 44 | "macFrameworkPath": [ 45 | "/System/Library/Frameworks", 46 | "/Library/Frameworks" 47 | ] 48 | } 49 | ], 50 | "version": 3 51 | } 52 | -------------------------------------------------------------------------------- /FujitsuWebServer.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | // Send temperature interval 12 | const int REFRESH_INTERVAL = 60 * 1000; // ms 13 | int lastRefresh = 0; 14 | 15 | // ESP8266 16 | const int led = BUILTIN_LED; 17 | 18 | // temp sensor 19 | const int pinDHT11 = D2; 20 | SimpleDHT11 dht11; 21 | byte currentRoomTemp = 0; 22 | byte currentRoomHumidity = 0; 23 | 24 | // AC 25 | IRFujitsuAC fujitsu(D0); 26 | int currentTemp = 18; 27 | int currentSwing = FUJITSU_AC_SWING_OFF; 28 | int currentMode = FUJITSU_AC_MODE_COOL; 29 | int currentFanSpeed = FUJITSU_AC_FAN_HIGH; 30 | 31 | // WiFi 32 | const char* ssid = "Biscayne2"; 33 | const char* password = "1212felipecoury"; 34 | 35 | // HTTP Server 36 | ESP8266WebServer server(80); 37 | 38 | // HTTP Client 39 | const char* host = "fcoury-sensit.herokuapp.com"; 40 | const int httpsPort = 443; 41 | 42 | WiFiClientSecure client; 43 | 44 | // ---------------------------- 45 | // Main code - setup and loop 46 | // ---------------------------- 47 | 48 | void setup() { 49 | // Serial setup 50 | Serial.begin(115200); 51 | 52 | // LED setup 53 | pinMode(led, OUTPUT); 54 | 55 | // AC setup 56 | Serial.println("AC setup"); 57 | fujitsu.begin(); 58 | 59 | // WiFi setup 60 | WiFi.begin(ssid, password); 61 | Serial.println(""); 62 | 63 | // Wait for WiFi connection 64 | while (WiFi.status() != WL_CONNECTED) { 65 | delay(500); 66 | Serial.print("."); 67 | } 68 | Serial.println(""); 69 | Serial.print("Connected to "); 70 | Serial.println(ssid); 71 | Serial.print("IP address: "); 72 | Serial.println(WiFi.localIP()); 73 | 74 | if (MDNS.begin("esp8266")) { 75 | Serial.println("MDNS Responder Started"); 76 | } 77 | 78 | // HTTP Server 79 | server.on("/", handleIndex); 80 | server.on("/settemp", handleSetTemp); 81 | server.on("/dectemp", handleDecTemp); 82 | server.on("/inctemp", handleIncTemp); 83 | server.on("/gettemp", handleGetTemp); 84 | server.on("/curtemp", handleCurrTemp); 85 | server.on("/nextfan", handleNextFan); 86 | server.on("/setfan", handleSetFan); 87 | server.on("/status", handleGetStatus); 88 | server.on("/turnon", handleTurnOn); 89 | server.on("/turnoff", handleTurnOff); 90 | server.begin(); 91 | 92 | // sends a ready blink 93 | delay(200); 94 | blink(100); 95 | } 96 | 97 | void loop() { 98 | // HTTP server 99 | server.handleClient(); 100 | 101 | if (millis() - lastRefresh >= REFRESH_INTERVAL) { 102 | lastRefresh = millis(); 103 | sendTemp(); 104 | } 105 | } 106 | 107 | 108 | void blink(int pause) { 109 | digitalWrite(led, 0); 110 | delay(pause); 111 | digitalWrite(led, 1); 112 | } 113 | 114 | void sendTemp() { 115 | byte temperature = 0; 116 | byte humidity = 0; 117 | int err = SimpleDHTErrSuccess; 118 | if ((err = dht11.read(pinDHT11, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { 119 | Serial.print("Read DHT11 failed, err="); Serial.println(err);delay(1000); 120 | return; 121 | } 122 | 123 | currentRoomTemp = temperature; 124 | currentRoomHumidity = humidity; 125 | send(temperature, humidity); 126 | } 127 | 128 | 129 | void send(byte temperature, byte humidity) { 130 | if (!client.connect(host, httpsPort)) { 131 | Serial.println("connection failed"); 132 | return; 133 | } 134 | 135 | String url = "/"; 136 | Serial.print("requesting URL: "); 137 | Serial.println(url); 138 | 139 | String data = "{\"temperature\":" + String(temperature) + ",\"humidity\":" + String(humidity) + "}"; 140 | 141 | String request = String("POST ") + url + " HTTP/1.1\r\n" + 142 | "Host: " + host + "\r\n" + 143 | "User-Agent: BuildFailureDetectorESP8266\r\n" + 144 | "Content-Type: application/json\r\n" + 145 | "Content-Length: " + data.length() + "\r\n" + 146 | "Connection: close\r\n\r\n" + data + "\r\n"; 147 | 148 | Serial.print("Data: "); 149 | Serial.println(data); 150 | 151 | Serial.println("Request: "); 152 | Serial.println(request); 153 | client.print(request); 154 | 155 | Serial.println("request sent"); 156 | while (client.connected()) { 157 | String line = client.readStringUntil('\n'); 158 | if (line == "\r") { 159 | Serial.println("headers received"); 160 | break; 161 | } 162 | } 163 | String line = client.readStringUntil('\n'); 164 | if (line.startsWith("{\"state\":\"success\"")) { 165 | Serial.println("esp8266/Arduino CI successfull!"); 166 | } else { 167 | Serial.println("esp8266/Arduino CI has failed"); 168 | } 169 | Serial.println("reply was:"); 170 | Serial.println("=========="); 171 | Serial.println(line); 172 | Serial.println("=========="); 173 | Serial.println("closing connection"); 174 | blink(200); 175 | } 176 | 177 | // ------------ 178 | // AC helpers 179 | // ------------ 180 | 181 | void incTemp() { 182 | currentTemp += 1; 183 | if (currentTemp > 24) { 184 | currentTemp = 24; 185 | } 186 | sendAC(-1); 187 | } 188 | 189 | void decTemp() { 190 | currentTemp -= 1; 191 | if (currentTemp < 18) { 192 | currentTemp = 18; 193 | } 194 | sendAC(-1); 195 | } 196 | 197 | void cycleFanSpeed() { 198 | currentFanSpeed += 1; 199 | if (currentFanSpeed > FUJITSU_AC_FAN_QUIET) { 200 | currentFanSpeed = FUJITSU_AC_FAN_AUTO; 201 | } 202 | sendAC(-1); 203 | } 204 | 205 | void setFanSpeed(int speed) { 206 | currentFanSpeed = speed; 207 | sendAC(-1); 208 | } 209 | 210 | void setTemp(int temp) { 211 | currentTemp = temp; 212 | sendAC(FUJITSU_AC_CMD_TURN_ON); 213 | } 214 | 215 | void sendAC(int command) { 216 | Serial.println("Sending AC command"); 217 | 218 | if (command > -1) { 219 | Serial.print("command: "); 220 | Serial.print(command); 221 | Serial.print(" | "); 222 | fujitsu.setCmd(command); 223 | } 224 | Serial.print("swing: "); 225 | Serial.print(currentSwing); 226 | fujitsu.setSwing(currentSwing); 227 | Serial.print(" | mode: "); 228 | Serial.print(currentMode); 229 | fujitsu.setMode(currentMode); 230 | Serial.print(" | fanSpeed: "); 231 | Serial.print(currentFanSpeed); 232 | fujitsu.setFanSpeed(currentFanSpeed); 233 | Serial.print(" | temperature: "); 234 | Serial.println(currentTemp); 235 | fujitsu.setTemp(currentTemp); 236 | fujitsu.send(); 237 | 238 | sendACStatus(); 239 | } 240 | 241 | String getSwing() { 242 | if (currentSwing == FUJITSU_AC_SWING_OFF) { 243 | return "off"; 244 | } else if (currentSwing == FUJITSU_AC_SWING_VERT) { 245 | return "vertical"; 246 | } else if (currentSwing == FUJITSU_AC_SWING_HORIZ) { 247 | return "horizontal"; 248 | } else if (currentSwing == FUJITSU_AC_SWING_BOTH) { 249 | return "both"; 250 | } else { 251 | return "unknown"; 252 | } 253 | } 254 | 255 | String getMode() { 256 | if (currentMode == FUJITSU_AC_MODE_AUTO) { 257 | return "auto"; 258 | } else if (currentMode == FUJITSU_AC_MODE_COOL) { 259 | return "cool"; 260 | } else if (currentMode == FUJITSU_AC_MODE_DRY) { 261 | return "dry"; 262 | } else if (currentMode == FUJITSU_AC_MODE_FAN) { 263 | return "fan"; 264 | } else if (currentMode == FUJITSU_AC_MODE_HEAT) { 265 | return "heat"; 266 | } else { 267 | return "unknown"; 268 | } 269 | } 270 | 271 | String getFanSpeed() { 272 | if (currentFanSpeed == FUJITSU_AC_FAN_AUTO) { 273 | return "auto"; 274 | } else if (currentFanSpeed == FUJITSU_AC_FAN_HIGH) { 275 | return "high"; 276 | } else if (currentFanSpeed == FUJITSU_AC_FAN_MED) { 277 | return "med"; 278 | } else if (currentFanSpeed == FUJITSU_AC_FAN_LOW) { 279 | return "low"; 280 | } else if (currentFanSpeed == FUJITSU_AC_FAN_QUIET) { 281 | return "quiet"; 282 | } else { 283 | return "unknown"; 284 | } 285 | } 286 | 287 | void sendACStatus() { 288 | String data = "\"temperature\": " + String(currentTemp); 289 | data += ", \"swing\": \"" + getSwing() + "\""; 290 | data += ", \"mode\": \"" + getMode() + "\""; 291 | data += ", \"fanSpeed\": \"" + getFanSpeed() + "\""; 292 | data += ", \"swingValue\": " + String(currentSwing); 293 | data += ", \"modeValue\": " + String(currentMode); 294 | data += ", \"fanSpeedValue\": " + String(currentFanSpeed); 295 | 296 | jsonData(data); 297 | } 298 | 299 | // --------------------- 300 | // HTTP server helpers 301 | // --------------------- 302 | 303 | void jsonError(int code, String error) { 304 | server.send(code, "application/json", "{\"ok\": false, \"error\": \"" + error + "\"}"); 305 | blink(200); 306 | blink(200); 307 | } 308 | 309 | void jsonData(String data) { 310 | server.send(200, "application/json", "{\"ok\": true, " + data + "}"); 311 | blink(200); 312 | } 313 | 314 | void jsonOK() { 315 | server.send(200, "application/json", "{\"ok\": true}"); 316 | blink(200); 317 | } 318 | 319 | void html(String body) { 320 | server.send(200, "text/html", body); 321 | blink(200); 322 | } 323 | 324 | // -------------- 325 | // HTML helpers 326 | // -------------- 327 | 328 | String rowDiv = "
\n"; 329 | String endDiv = "
\n"; 330 | 331 | String addButton(int colSize, String label, String url) { 332 | return "
\n" + 333 | " \n" + 334 | "
\n"; 335 | } 336 | 337 | // ---------------------- 338 | // HTTP server handlers 339 | // ---------------------- 340 | 341 | void handleIndex() { 342 | String body = "\n"; 343 | body += "\n"; 344 | body += " \n"; 345 | body += " \n"; 346 | body += " \n"; 347 | body += " \n"; 348 | body += " \n"; 349 | body += " \n"; 350 | body += " \n"; 351 | 352 | body += "
"; 353 | 354 | body += rowDiv; 355 | body += addButton(6, "AC On", "turnon"); 356 | body += addButton(6, "AC Off", "turnoff"); 357 | body += endDiv; 358 | 359 | body += rowDiv; 360 | body += addButton(4, "-", "dectemp"); 361 | body += addButton(4, "+", "inctemp"); 362 | body += addButton(4, "Fan", "nextfan"); 363 | body += endDiv; 364 | 365 | body += " \n"; 366 | body += " \n"; 367 | 368 | body += "\n"; 394 | 395 | body += " \n"; 396 | body += "\n"; 397 | 398 | html(body); 399 | } 400 | 401 | void handleCurrTemp() { 402 | String data = "\"temperature\":" + String(currentRoomTemp) + ",\"humidity\":" + String(currentRoomHumidity); 403 | jsonData(data); 404 | } 405 | 406 | void handleSetTemp() { 407 | String temperature = server.arg("temperature"); 408 | if (temperature == "") { 409 | jsonError(422, "Missing temperature"); 410 | return; 411 | } 412 | 413 | setTemp(temperature.toInt()); 414 | } 415 | 416 | void handleIncTemp() { 417 | Serial.print("Increasing current temperature: "); 418 | Serial.println(currentTemp); 419 | incTemp(); 420 | } 421 | 422 | void handleDecTemp() { 423 | Serial.print("Decreasing current temperature: "); 424 | Serial.println(currentTemp); 425 | decTemp(); 426 | } 427 | 428 | void handleSetFan() { 429 | String speed = server.arg("speed"); 430 | 431 | if (speed == "") { 432 | jsonError(422, "missing speed parameter"); 433 | return; 434 | } 435 | 436 | if (speed == "high") { 437 | setFanSpeed(FUJITSU_AC_FAN_HIGH); 438 | } else if (speed == "med") { 439 | setFanSpeed(FUJITSU_AC_FAN_MED); 440 | } else if (speed == "low") { 441 | setFanSpeed(FUJITSU_AC_FAN_LOW); 442 | } else if (speed == "auto") { 443 | setFanSpeed(FUJITSU_AC_FAN_AUTO); 444 | } else if (speed == "quiet") { 445 | setFanSpeed(FUJITSU_AC_FAN_QUIET); 446 | } else { 447 | jsonError(422, "invalid fan speed: " + speed); 448 | } 449 | } 450 | 451 | void handleGetStatus() { 452 | sendACStatus(); 453 | } 454 | 455 | void handleGetTemp() { 456 | byte temperature = 0; 457 | byte humidity = 0; 458 | int err = SimpleDHTErrSuccess; 459 | if ((err = dht11.read(pinDHT11, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) { 460 | Serial.print("Read DHT11 failed, err="); Serial.println(err); 461 | jsonError(500, "Could not get temperature. Error: " + err); 462 | delay(1000); 463 | return; 464 | } 465 | 466 | jsonData("\"temperature\":" + String(temperature) + ", \"humidity\":" + String(humidity)); 467 | } 468 | 469 | void handleTurnOn() { 470 | sendAC(FUJITSU_AC_CMD_TURN_ON); 471 | } 472 | 473 | void handleTurnOff() { 474 | sendAC(FUJITSU_AC_CMD_TURN_OFF); 475 | } 476 | 477 | void handleNextFan() { 478 | cycleFanSpeed(); 479 | } 480 | 481 | 482 | --------------------------------------------------------------------------------