├── README.md └── BlynkIR └── BlynkIR.ino /README.md: -------------------------------------------------------------------------------- 1 | # arduino-ESP32-BlynkIR 2 | 3 | ### App project setup 4 | Time input widget linked with V0 for Start time 5 | Time input widget linked with V1 for Stop time 6 | Value display linked to V3 to display the current time 7 | LED linked to V2 to display when AC is ON 8 | RTC widget 9 | 10 | ### Program description 11 | This Blynk app is used to control an AC unit with IR signal 12 | Works with an ESP32 dev board and IR LED 13 | The IR LED is connected to IO26 of the ESP32 14 | With the Blynk app you set the start and stop time 15 | and the program will send the start/stop IR command when the time comes 16 | 17 | ### Author 18 | L-A Boulanger 19 | -------------------------------------------------------------------------------- /BlynkIR/BlynkIR.ino: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | Download latest Blynk library here: 3 | https://github.com/blynkkk/blynk-library/releases/latest 4 | Blynk is a platform with iOS and Android apps to control 5 | Arduino, Raspberry Pi and the likes over the Internet. 6 | You can easily build graphic interfaces for all your 7 | projects by simply dragging and dropping widgets. 8 | Downloads, docs, tutorials: http://www.blynk.cc 9 | Sketch generator: http://examples.blynk.cc 10 | Blynk community: http://community.blynk.cc 11 | Follow us: http://www.fb.com/blynkapp 12 | http://twitter.com/blynk_app 13 | Blynk library is licensed under MIT license 14 | This example code is in public domain. 15 | ************************************************************* 16 | App project setup: 17 | Time input widget linked with V0 for Start time 18 | Time input widget linked with V1 for Stop time 19 | Value display linked to V3 to display the current time 20 | LED linked to V2 to display when AC is ON 21 | RTC widget 22 | Program description: 23 | This Blynk app is used to control an AC unit with IR signal 24 | Works with a ESP32 dev board and IR LED 25 | The IR LED is connected to IO26 of the ESP32 26 | With the Blynk app you set the start and stop time 27 | and the program will send the start/stop IR command when the time comes 28 | Author 29 | L-A Boulanger 30 | 31 | *************************************************************/ 32 | 33 | //Includes 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "driver/rmt.h" 40 | #include "driver/periph_ctrl.h" 41 | #include "soc/rmt_reg.h" 42 | 43 | 44 | //Infrared remote peripheral defines 45 | #define RMT_TX_CARRIER_EN 1 /*!< Enable carrier for IR transmitter test with IR led */ 46 | #define RMT_CARRIER_FREQ 38750 47 | #define RMT_CARRIER_DUTY 45 48 | #define RMT_TX_CHANNEL RMT_CHANNEL_1 /*!< RMT channel for transmitter */ 49 | #define RMT_TX_GPIO_NUM GPIO_NUM_26 /*!< GPIO number for transmitter signal */ 50 | #define RMT_CLK_DIV 100 /*!< RMT counter clock divider */ 51 | #define RMT_TICK_10_US (80000000/RMT_CLK_DIV/100000) /*!< RMT counter value for 10 us.(Source clock is APB clock) */ 52 | 53 | #define NEC_HEADER_HIGH_US 3200 /*!< TECO protocol header: pulses for 3.2ms */ 54 | #define NEC_HEADER_LOW_US 1600 /*!< TECO protocol header: low for 1.6ms*/ 55 | #define NEC_BIT_ONE_HIGH_US 400 /*!< TECO protocol data bit 1: positive 400us */ 56 | #define NEC_BIT_ONE_LOW_US 1200 /*!< TECO protocol data bit 1: negative 1200us */ 57 | #define NEC_BIT_ZERO_HIGH_US 400 /*!< TECO protocol data bit 0: positive 400us */ 58 | #define NEC_BIT_ZERO_LOW_US 400 /*!< TECO protocol data bit 0: negative 400us */ 59 | #define NEC_BIT_END 0 /*!< NEC protocol end: */ 60 | #define NEC_BIT_MARGIN 20 /*!< NEC parse margin time */ 61 | 62 | #define NEC_ITEM_DURATION(d) ((d & 0x7fff)*10/RMT_TICK_10_US) /*!< Parse duration time from memory register value */ 63 | #define NEC_DATA_ITEM_NUM 74 /*!< NEC code item number: header + 32bit data + end */ 64 | #define RMT_TX_DATA_NUM 1 /*!< NEC tx test data number */ 65 | #define rmt_item32_tIMEOUT_US 9500 /*!< RMT receiver timeout value(us) */ 66 | 67 | 68 | #define BLYNK_PRINT Serial 69 | #define GPIO_LED GPIO_NUM_27 /*LED output pin 27 */ 70 | 71 | 72 | 73 | // You should get Auth Token in the Blynk App. 74 | // Go to the Project Settings (nut icon). 75 | char auth[] = "1234567890"; //write your own 76 | 77 | // Your WiFi credentials. 78 | // Set password to "" for open networks. 79 | char ssid[] = "Poutineville"; 80 | char pass[] = "poutinesquicksquick"; 81 | 82 | BlynkTimer timer; 83 | WidgetRTC rtc; 84 | WidgetLED led1(V2); 85 | 86 | String startTime, stopTime; 87 | int currentHour = 0, currentMin = 0; 88 | int startHour = 1, startMin = 1; 89 | int stopHour = 1, stopMin = 1; 90 | boolean AC_ON = false; 91 | 92 | //IR functions 93 | //Build register value of waveform for NEC one data bit 94 | static inline void nec_fill_item_level(rmt_item32_t* item, int high_us, int low_us) 95 | { 96 | item->level0 = 1; 97 | item->duration0 = (high_us) / 10 * RMT_TICK_10_US; 98 | item->level1 = 0; 99 | item->duration1 = (low_us) / 10 * RMT_TICK_10_US; 100 | } 101 | 102 | 103 | //Generate NEC header value 104 | static void nec_fill_item_header(rmt_item32_t* item) 105 | { 106 | nec_fill_item_level(item, NEC_HEADER_HIGH_US, NEC_HEADER_LOW_US); 107 | } 108 | 109 | 110 | //Generate NEC data bit 1 111 | static void nec_fill_item_bit_one(rmt_item32_t* item) 112 | { 113 | nec_fill_item_level(item, NEC_BIT_ONE_HIGH_US, NEC_BIT_ONE_LOW_US); 114 | } 115 | 116 | 117 | //Generate NEC data bit 0 118 | static void nec_fill_item_bit_zero(rmt_item32_t* item) 119 | { 120 | nec_fill_item_level(item, NEC_BIT_ZERO_HIGH_US, NEC_BIT_ZERO_LOW_US); 121 | } 122 | 123 | 124 | //Generate NEC end signal 125 | static void nec_fill_item_end(rmt_item32_t* item) 126 | { 127 | nec_fill_item_level(item, NEC_BIT_END, 0x7fff); 128 | } 129 | 130 | 131 | 132 | //Build NEC 32bit waveform. 133 | static int nec_build_items(int channel, rmt_item32_t* item) 134 | { 135 | 136 | //1st byte 00110000 137 | nec_fill_item_header(item++); 138 | nec_fill_item_bit_zero(item++); 139 | nec_fill_item_bit_zero(item++); 140 | nec_fill_item_bit_one(item++); 141 | nec_fill_item_bit_one(item++); 142 | nec_fill_item_bit_zero(item++); 143 | nec_fill_item_bit_zero(item++); 144 | nec_fill_item_bit_zero(item++); 145 | nec_fill_item_bit_zero(item++); 146 | 147 | //2nd byte 11111111 148 | nec_fill_item_bit_one(item++); 149 | nec_fill_item_bit_one(item++); 150 | nec_fill_item_bit_one(item++); 151 | nec_fill_item_bit_one(item++); 152 | nec_fill_item_bit_one(item++); 153 | nec_fill_item_bit_one(item++); 154 | nec_fill_item_bit_one(item++); 155 | nec_fill_item_bit_one(item++); 156 | 157 | //3rd byte 01011111 158 | nec_fill_item_bit_zero(item++); 159 | nec_fill_item_bit_one(item++); 160 | nec_fill_item_bit_zero(item++); 161 | nec_fill_item_bit_one(item++); 162 | nec_fill_item_bit_one(item++); 163 | nec_fill_item_bit_one(item++); 164 | nec_fill_item_bit_one(item++); 165 | nec_fill_item_bit_one(item++); 166 | 167 | //4th byte 00111111 168 | nec_fill_item_bit_zero(item++); 169 | nec_fill_item_bit_zero(item++); 170 | nec_fill_item_bit_one(item++); 171 | nec_fill_item_bit_one(item++); 172 | nec_fill_item_bit_one(item++); 173 | nec_fill_item_bit_one(item++); 174 | nec_fill_item_bit_one(item++); 175 | nec_fill_item_bit_one(item++); 176 | 177 | //5th byte 00011111 178 | nec_fill_item_bit_zero(item++); 179 | nec_fill_item_bit_zero(item++); 180 | nec_fill_item_bit_zero(item++); 181 | nec_fill_item_bit_one(item++); 182 | nec_fill_item_bit_one(item++); 183 | nec_fill_item_bit_one(item++); 184 | nec_fill_item_bit_one(item++); 185 | nec_fill_item_bit_one(item++); 186 | 187 | //6th byte 00111010 188 | nec_fill_item_bit_zero(item++); 189 | nec_fill_item_bit_zero(item++); 190 | nec_fill_item_bit_one(item++); 191 | nec_fill_item_bit_one(item++); 192 | nec_fill_item_bit_one(item++); 193 | nec_fill_item_bit_zero(item++); 194 | nec_fill_item_bit_one(item++); 195 | nec_fill_item_bit_zero(item++); 196 | 197 | //7th byte 00011001 198 | nec_fill_item_bit_zero(item++); 199 | nec_fill_item_bit_zero(item++); 200 | nec_fill_item_bit_zero(item++); 201 | nec_fill_item_bit_one(item++); 202 | nec_fill_item_bit_one(item++); 203 | nec_fill_item_bit_zero(item++); 204 | nec_fill_item_bit_zero(item++); 205 | nec_fill_item_bit_one(item++); 206 | 207 | //8th byte 00100000 208 | nec_fill_item_bit_zero(item++); 209 | nec_fill_item_bit_zero(item++); 210 | nec_fill_item_bit_one(item++); 211 | nec_fill_item_bit_zero(item++); 212 | nec_fill_item_bit_zero(item++); 213 | nec_fill_item_bit_zero(item++); 214 | nec_fill_item_bit_zero(item++); 215 | nec_fill_item_bit_zero(item++); 216 | 217 | //9th byte 10000000 218 | nec_fill_item_bit_one(item++); 219 | nec_fill_item_bit_zero(item++); 220 | nec_fill_item_bit_zero(item++); 221 | nec_fill_item_bit_zero(item++); 222 | nec_fill_item_bit_zero(item++); 223 | nec_fill_item_bit_zero(item++); 224 | nec_fill_item_bit_zero(item++); 225 | nec_fill_item_bit_zero(item++); 226 | 227 | nec_fill_item_bit_zero(item++); 228 | /* 229 | i++; 230 | for(j = 0; j < 16; j++) { 231 | if(cmd_data & 0x1) { 232 | nec_fill_item_bit_one(item); 233 | } else { 234 | nec_fill_item_bit_zero(item); 235 | } 236 | item++; 237 | i++; 238 | cmd_data >>= 1; 239 | } 240 | */ 241 | nec_fill_item_end(item); 242 | 243 | } 244 | 245 | 246 | //RMT transmitter initialization 247 | static void nec_tx_init() 248 | { 249 | rmt_config_t rmt_tx; 250 | rmt_tx.channel = RMT_TX_CHANNEL; 251 | rmt_tx.gpio_num = RMT_TX_GPIO_NUM; 252 | rmt_tx.mem_block_num = 1; 253 | rmt_tx.clk_div = RMT_CLK_DIV; 254 | rmt_tx.tx_config.loop_en = false; 255 | rmt_tx.tx_config.carrier_duty_percent = RMT_CARRIER_DUTY; 256 | rmt_tx.tx_config.carrier_freq_hz = RMT_CARRIER_FREQ; 257 | rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH; 258 | rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN; 259 | rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; 260 | rmt_tx.tx_config.idle_output_en = true; 261 | rmt_tx.rmt_mode = RMT_MODE_TX; 262 | rmt_config(&rmt_tx); 263 | rmt_driver_install(rmt_tx.channel, 0, 0); 264 | } 265 | 266 | 267 | 268 | //RMT transmitter demo, this task will periodically send NEC data. (100 * 32 bits each time.) 269 | static void rmt_example_nec_tx_task() //void *pvParameters 270 | { 271 | nec_tx_init(); 272 | 273 | int nec_tx_num = RMT_TX_DATA_NUM; 274 | 275 | size_t size = (sizeof(rmt_item32_t) * NEC_DATA_ITEM_NUM * nec_tx_num); 276 | //each item represent a cycle of waveform. 277 | rmt_item32_t* item = (rmt_item32_t*) malloc(size); 278 | int item_num = NEC_DATA_ITEM_NUM * nec_tx_num; 279 | memset((void*) item, 0, size); 280 | 281 | nec_build_items(RMT_TX_CHANNEL, item); 282 | //Serial.println("DBG - rmt_build_items done"); 283 | 284 | //To send data according to the waveform items. 285 | rmt_write_items(RMT_TX_CHANNEL, item, item_num, true); 286 | //Serial.println("DBG - rmt_write_items done"); 287 | 288 | //Wait until sending is done. 289 | rmt_wait_tx_done(RMT_TX_CHANNEL); 290 | //Serial.println("DBG - tx done"); 291 | 292 | //before we free the data, make sure sending is already done. 293 | free(item); 294 | //Serial.println("DBG - free(item) done"); 295 | return; 296 | } 297 | 298 | 299 | //Function that gets start time from Blynk app 300 | BLYNK_WRITE(V0) { 301 | TimeInputParam t(param); 302 | startHour = t.getStartHour(); 303 | startMin = t.getStartMinute(); 304 | startTime = String(t.getStartHour()) + ":" + String(t.getStartMinute()); 305 | Serial.println(String("Start time: ") + startTime); 306 | } 307 | 308 | //Function that gets stop time from Blynk app 309 | BLYNK_WRITE(V1) { 310 | TimeInputParam t(param); 311 | stopHour = t.getStartHour(); 312 | stopMin = t.getStartMinute(); 313 | stopTime = String(t.getStartHour()) + ":" + String(t.getStartMinute()); 314 | Serial.println(String("Stop time: ") + stopTime); 315 | } 316 | 317 | // Digital clock display of the time 318 | void clockDisplay() 319 | { 320 | // You can call hour(), minute(), ... at any time 321 | // Please see Time library examples for details 322 | 323 | String currentTime = String(hour()) + ":" + minute(); 324 | currentHour = hour(); 325 | currentMin = minute(); 326 | //String currentDate = String(day()) + " " + month() + " " + year(); 327 | Serial.print("Current time: "); 328 | Serial.println(currentTime); 329 | //Serial.print(currentDate); 330 | //Serial.println(); 331 | 332 | // Send time to the App 333 | Blynk.virtualWrite(V3, currentTime); 334 | // Send date to the App 335 | //Blynk.virtualWrite(V2, currentDate); 336 | 337 | } 338 | 339 | void setup() 340 | { 341 | // Debug console 342 | Serial.begin(115200); 343 | pinMode(GPIO_LED, OUTPUT); 344 | 345 | Blynk.begin(auth, ssid, pass); 346 | // You can also specify server: 347 | //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 8442); 348 | //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8442); 349 | 350 | // Begin synchronizing time 351 | rtc.begin(); 352 | timer.setInterval(10000L, clockDisplay); 353 | 354 | led1.off(); 355 | } 356 | 357 | void loop() 358 | { 359 | Blynk.run(); 360 | timer.run(); 361 | 362 | //Checks if it's time to turn on or off the AC 363 | if (startHour == currentHour && startMin == currentMin && AC_ON == false) { 364 | digitalWrite(GPIO_LED, HIGH); 365 | led1.on(); 366 | rmt_example_nec_tx_task(); //sends IR start/stop command 367 | Serial.println("IR command sent"); 368 | AC_ON = true; 369 | } 370 | else if (stopHour == currentHour && stopMin == currentMin && AC_ON == true) { 371 | digitalWrite(GPIO_LED, LOW); 372 | led1.off(); 373 | rmt_example_nec_tx_task(); //sends IR start/stop command 374 | Serial.println("IR command sent"); 375 | AC_ON = false; 376 | } 377 | 378 | } 379 | --------------------------------------------------------------------------------