Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/arduino-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Arduino Build CI

on:
push:
branches: [ "**" ]
pull_request:
branches: [ "**" ]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
sketch:
- path: ac_control/ir_sender
name: ir_sender
- path: ac_control/ir_receiver
name: ir_receiver
profile:
- uno
- esp8266
- esp32

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Arduino CLI
uses: arduino/setup-arduino-cli@v1

- name: Compile sketch with profile ${{ matrix.profile }}
run: |
arduino-cli compile --profile ${{ matrix.profile }} ${{ matrix.sketch.path }}

- name: Build summary
run: |
echo "✅ Successfully built ${{ matrix.sketch.name }} for profile ${{ matrix.profile }}"
76 changes: 23 additions & 53 deletions ac_control/ir_receiver/ir_receiver.ino
Original file line number Diff line number Diff line change
@@ -1,73 +1,43 @@
#define sprint Serial.print
#define sprint Serial.print
#define sprintln Serial.println
#include <IRremote.h>
int RECV_PIN = 11;


IRrecv irrecv(RECV_PIN);
#include <IRremote.hpp> // IRremote 4.4.1 from Library Manager


decode_results results;
int RECV_PIN = 11;
unsigned long timeBegin;
int c = 1;
unsigned long timeBegin;

void setup()
{
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
IrReceiver.begin(RECV_PIN, ENABLE_LED_FEEDBACK); // Start the receiver
timeBegin = micros();

Serial.println(F("Ready to receive IR signals"));
}

void loop() {
if (IrReceiver.decode()) {
// Print counter
sprintln(c);
c++;

// Use built-in print functions from IRremote library
IrReceiver.printIRResultShort(&Serial);
Serial.println();

// Print as C array for use in sender
IrReceiver.printIRSendUsage(&Serial);

if (irrecv.decode(&results)) {
dump(&results);
// ========
Serial.println(results.value, HEX);
Serial.print("rawlen ");
Serial.println(results.rawlen);
Serial.print("decode type ");
Serial.println(results.decode_type);
// Additional details
Serial.print("Protocol: ");
Serial.println(IrReceiver.decodedIRData.protocol);
Serial.print("Decoded value: 0x");
Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);

unsigned long timeEnd = micros();
unsigned long duration = timeEnd - timeBegin;
double averageDuration = (double)duration / 1000.0;
Serial.println(averageDuration);
// if(results.value==0xA1026EFF) {
// Serial.println("turning off");
// }
irrecv.resume(); // Receive the next value

IrReceiver.resume(); // Receive the next value
}
}

void dump(decode_results *results) {
int count = results->rawlen;
sprintln(c);
c++;
sprintln("For IR Scope: ");
for (int i = 1; i < count; i++) {
sprint("0x");
sprint((unsigned int)results->rawbuf[i], HEX);
sprint(" ");
}

sprintln("");
sprintln("For Arduino sketch: ");
sprint("unsigned int raw[");
sprint(count, DEC);
sprint("] = {");
for (int i = 1; i < count; i++) {
sprint("0x");
sprint((unsigned int)results->rawbuf[i], HEX);
sprint(",");
}
sprint("};");
sprintln("");
sprint("irsend.sendRaw(raw,");
sprint(count, DEC);
sprint(",38);");
sprintln("");
sprintln("");
}
21 changes: 21 additions & 0 deletions ac_control/ir_receiver/sketch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
profiles:
uno:
fqbn: arduino:avr:uno
platforms:
- platform: arduino:avr (1.8.6)
libraries:
- IRremote (4.4.1)
esp8266:
fqbn: esp8266:esp8266:nodemcuv2
platforms:
- platform: esp8266:esp8266 (3.1.2)
platform_index_url: https://arduino.esp8266.com/stable/package_esp8266com_index.json
libraries:
- IRremote (4.4.1)
esp32:
fqbn: esp32:esp32:esp32
platforms:
- platform: esp32:esp32 (3.3.2)
platform_index_url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
libraries:
- IRremote (4.4.1)
55 changes: 48 additions & 7 deletions ac_control/ir_sender/ir_sender.ino
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#include <IRremote.hpp> // IRremote 4.1.2 from Library Manager
#include <IRremote.hpp> // IRremote 4.4.1 from Library Manager

unsigned long period = 7200000;
unsigned long last_trigger = 0;
// PIR motion sensor configuration
#define PIR_PIN 2 // GPIO pin connected to PIR sensor output
#define MOTION_TIMEOUT 3600000 // 1 hour in milliseconds (60 * 60 * 1000)

unsigned long last_motion_time = 0;
bool ac_is_off = false; // Track whether we've already sent the off command

//4467 4347 608 1542 609 493 582 1568 582 493 582 493 582 493 582 493 582 1568 582 1568 583 493 582 493 582 1570 581 1570 581 495 580 1571 580 1571 580 495 580 1571 580 1571 580 495 580 1571 580 1571 580 495 581 1571 579 1571 580 1571 580 1571 580 1571 580 1571 580 1571 580 1571 580 1571 580 1572 579 1571 580 1571 580 1571 580 1571 580 1572 579 1571 580 1572 579 496 579 1572 579 1572 579 1572 579 496 579 1572 579 1572 579 1572 580 5167 4439 4377 579 496 579 1572 579 497 578 1572 579 1572 579 1572 579 1573 578 497 578 497 578 1573 578 1573 578 497 578 497 578 1573 578 497 578 497 578 1573 578 497 578 497 578 1573 578 497 578 498 577 1573 578 498 577 498 577 498 577 498 577 498 577 498 577 498 577 499 576 522 553 522 554 522 553 522 553 522 553 522 553 522 553 522 553 522 553 1598 553 522 553 522 554 522 553 1598 553 522 553 522 553 522 553
uint16_t on_code[199] = {0x1173, 0x10fb, 0x260, 0x606, 0x261, 0x1ed, 0x246, 0x620, 0x246, 0x1ed, 0x246, 0x1ed, 0x246, 0x1ed, 0x246, 0x1ed, 0x246, 0x620, 0x246, 0x620, 0x247, 0x1ed, 0x246, 0x1ed, 0x246, 0x622, 0x245, 0x622, 0x245, 0x1ef, 0x244, 0x623, 0x244, 0x623, 0x244, 0x1ef, 0x244, 0x623, 0x244, 0x623, 0x244, 0x1ef, 0x244, 0x623, 0x244, 0x623, 0x244, 0x1ef, 0x245, 0x623, 0x243, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x624, 0x243, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x623, 0x244, 0x624, 0x243, 0x623, 0x244, 0x624, 0x243, 0x1f0, 0x243, 0x624, 0x243, 0x624, 0x243, 0x624, 0x243, 0x1f0, 0x243, 0x624, 0x243, 0x624, 0x243, 0x624, 0x244, 0x142f, 0x1157, 0x1119, 0x243, 0x1f0, 0x243, 0x624, 0x243, 0x1f1, 0x242, 0x624, 0x243, 0x624, 0x243, 0x624, 0x243, 0x625, 0x242, 0x1f1, 0x242, 0x1f1, 0x242, 0x625, 0x242, 0x625, 0x242, 0x1f1, 0x242, 0x1f1, 0x242, 0x625, 0x242, 0x1f1, 0x242, 0x1f1, 0x242, 0x625, 0x242, 0x1f1, 0x242, 0x1f1, 0x242, 0x625, 0x242, 0x1f1, 0x242, 0x1f2, 0x241, 0x625, 0x242, 0x1f2, 0x241, 0x1f2, 0x241, 0x1f2, 0x241, 0x1f2, 0x241, 0x1f2, 0x241, 0x1f2, 0x241, 0x1f2, 0x241, 0x1f3, 0x240, 0x20a, 0x229, 0x20a, 0x22a, 0x20a, 0x229, 0x20a, 0x229, 0x20a, 0x229, 0x20a, 0x229, 0x20a, 0x229, 0x20a, 0x229, 0x20a, 0x229, 0x63e, 0x229, 0x20a, 0x229, 0x20a, 0x22a, 0x20a, 0x229, 0x63e, 0x229, 0x20a, 0x229, 0x20a, 0x229, 0x20a, 0x229};
Expand All @@ -12,15 +16,52 @@ uint16_t temp_code[199] = {0x1113, 0x1176, 0x207, 0x655, 0x207, 0x20b, 0x207, 0x
uint16_t off_code[] = {0x2301, 0x11a8, 0x27e, 0x237, 0x27f, 0x684, 0x27f, 0x685, 0x27f, 0x239, 0x27d, 0x684, 0x27f, 0x686, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x685, 0x27f, 0x685, 0x27e, 0x238, 0x27e, 0x239, 0x27d, 0x239, 0x27d, 0x238, 0x27e, 0x238, 0x27e, 0x239, 0x27d, 0x238, 0x27e, 0x23a, 0x27c, 0x237, 0x27f, 0x238, 0x27e, 0x238, 0x27e, 0x684, 0x27f, 0x236, 0x280, 0x239, 0x27c, 0x238, 0x27e, 0x237, 0x27f, 0x687, 0x27d, 0x684, 0x27f, 0x685, 0x27f, 0x237, 0x27f, 0x685, 0x27e, 0x236, 0x280, 0x237, 0x27f, 0x685, 0x27e, 0x253, 0x263, 0x4e21, 0x27f, 0x236, 0x27f, 0x237, 0x27f, 0x235, 0x281, 0x253, 0x263, 0x235, 0x281, 0x236, 0x280, 0x238, 0x27f, 0x236, 0x280, 0x237, 0x27f, 0x236, 0x280, 0x236, 0x280, 0x236, 0x27f, 0x236, 0x280, 0x236, 0x280, 0x236, 0x27f, 0x683, 0x280, 0x235, 0x281, 0x237, 0x27f, 0x236, 0x280, 0x236, 0x280, 0x238, 0x27f, 0x237, 0x27f, 0x238, 0x27e, 0x235, 0x281, 0x235, 0x281, 0x235, 0x281, 0x237, 0x27f, 0x237, 0x27f, 0x684, 0x27f, 0x685, 0x27f, 0x687, 0x27c, 0x237, 0x27f, 0x9c48, 0x2302, 0x11aa, 0x27d, 0x237, 0x27f, 0x685, 0x27f, 0x684, 0x27f, 0x235, 0x281, 0x684, 0x280, 0x685, 0x27e, 0x237, 0x27f, 0x238, 0x27e, 0x684, 0x27f, 0x682, 0x281, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x27f, 0x236, 0x280, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x236, 0x280, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x684, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x236, 0x280, 0x682, 0x281, 0x685, 0x27e, 0x236, 0x280, 0x684, 0x27f, 0x685, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x686, 0x27e, 0x237, 0x27f, 0x4e25, 0x27e, 0x23a, 0x27c, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x239, 0x27d, 0x239, 0x27d, 0x238, 0x27e, 0x236, 0x280, 0x238, 0x27d, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x239, 0x27d, 0x236, 0x280, 0x238, 0x27e, 0x237, 0x27e, 0x236, 0x280, 0x237, 0x27e, 0x237, 0x27f, 0x236, 0x280, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x238, 0x27e, 0x685, 0x27e, 0x685, 0x27f, 0x685, 0x27f, 0x687, 0x27c, 0x9c4c, 0x2301, 0x11a7, 0x27e, 0x237, 0x27e, 0x685, 0x27f, 0x685, 0x27e, 0x238, 0x27e, 0x684, 0x280, 0x686, 0x27d, 0x239, 0x27d, 0x238, 0x27e, 0x6a1, 0x261, 0x685, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x238, 0x27e, 0x236, 0x280, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x685, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x684, 0x27f, 0x684, 0x27f, 0x684, 0x27f, 0x683, 0x280, 0x685, 0x27e, 0x238, 0x27e, 0x236, 0x27f, 0x685, 0x27f, 0x238, 0x27e, 0x4e21, 0x280, 0x236, 0x280, 0x235, 0x281, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x236, 0x280, 0x237, 0x27f, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x280, 0x237, 0x27f, 0x236, 0x280, 0x235, 0x280, 0x237, 0x27f, 0x236, 0x280, 0x236, 0x280, 0x236, 0x280, 0x685, 0x27f, 0x238, 0x27e, 0x684, 0x280, 0x683, 0x280, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x237, 0x27f, 0x236, 0x280, 0x236, 0x280, 0x685, 0x27e, 0x684, 0x27f, 0x9c4c, 0x22ff, 0x11a6, 0x280, 0x237, 0x27f, 0x236, 0x280, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x239, 0x27d, 0x23a, 0x27c, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x238, 0x27e, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x237, 0x27e, 0x239, 0x27d, 0x238, 0x27e, 0x238, 0x27e, 0x237, 0x27f, 0x238, 0x27e, 0x236, 0x280, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x236, 0x280, 0x684, 0x280, 0x236, 0x280, 0x684, 0x280, 0x237, 0x27f, 0x686, 0x27e, 0x236, 0x280, 0x684, 0x27f, 0x235, 0x281, 0x4e20, 0x280, 0x237, 0x27f, 0x238, 0x27e, 0x236, 0x280, 0x238, 0x27e, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x238, 0x27e, 0x237, 0x27f, 0x238, 0x27e, 0x235, 0x281, 0x237, 0x27f, 0x237, 0x27f, 0x239, 0x27d, 0x253, 0x262, 0x235, 0x280, 0x238, 0x27e, 0x238, 0x27d, 0x237, 0x27e, 0x236, 0x280, 0x237, 0x27f, 0x237, 0x27f, 0x237, 0x27f, 0x238, 0x27e, 0x236, 0x280, 0x238, 0x27e, 0x239, 0x27d, 0x237, 0x27e, 0x687, 0x27c, 0x237, 0x27e, 0x238, 0x27e};
void setup() {
pinMode (1, OUTPUT);
Serial.begin(9600); // does serial need to be open?
pinMode (PIR_PIN, INPUT);
Serial.begin(9600);
IrSender.begin(1);

// Initialize with current time - assume there's motion at startup
last_motion_time = millis();

// Send initial off code as before
IrSender.sendRaw(off_code, sizeof(off_code)/sizeof(off_code[0]), 38);
ac_is_off = true;

Serial.println("AC IR Sender with PIR Motion Sensor initialized");
Serial.print("Motion timeout: ");
Serial.print(MOTION_TIMEOUT / 1000);
Serial.println(" seconds");
}

void loop() {
// due to unsigned math being modulo, this period math still works when it wraps around after 50 days
if ((unsigned long)(millis() - last_trigger) > period) {
// Read PIR sensor state (HIGH = motion detected, LOW = no motion)
int motion_detected = digitalRead(PIR_PIN);

// If motion is detected, update the last motion time and reset AC off flag
if (motion_detected == HIGH) {
last_motion_time = millis();
if (ac_is_off) {
Serial.println("Motion detected! AC can be turned off again after timeout.");
ac_is_off = false; // Reset flag so we can turn off AC again after timeout
}
}

// Check if no motion timeout has been reached
// Due to unsigned math being modulo, this still works when millis() wraps around after ~50 days
unsigned long time_since_motion = (unsigned long)(millis() - last_motion_time);

if (time_since_motion > MOTION_TIMEOUT && !ac_is_off) {
// No motion for 1 hour and we haven't sent the off code yet
Serial.print("No motion for ");
Serial.print(MOTION_TIMEOUT / 1000);
Serial.println(" seconds. Sending AC OFF command.");

IrSender.sendRaw(off_code, sizeof(off_code)/sizeof(off_code[0]), 38);
last_trigger = millis();
ac_is_off = true;

Serial.println("AC OFF command sent.");
}

// Small delay to avoid excessive polling
delay(100);
}
21 changes: 21 additions & 0 deletions ac_control/ir_sender/sketch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
profiles:
uno:
fqbn: arduino:avr:uno
platforms:
- platform: arduino:avr (1.8.6)
libraries:
- IRremote (4.4.1)
esp8266:
fqbn: esp8266:esp8266:nodemcuv2
platforms:
- platform: esp8266:esp8266 (3.1.2)
platform_index_url: https://arduino.esp8266.com/stable/package_esp8266com_index.json
libraries:
- IRremote (4.4.1)
esp32:
fqbn: esp32:esp32:esp32
platforms:
- platform: esp32:esp32 (3.3.2)
platform_index_url: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
libraries:
- IRremote (4.4.1)