Initially, I had to manually modify the code to adjust the AC settings, which quickly became tedious. To streamline the process, I upgraded to two Wemos controllers connected over a local network and wrote some simple code that allows them to communicate. One controller is attached to a servo that adjusts the AC, while the other, located across the room, is connected to a temperature sensor. Now, the AC (or heater, depending on when the building switches over—New Yorkers know the struggle here) automatically turns on or off based on our preferences. I also designed and 3d printed a stronger base for the servo with a little box for the Wemo controller. Attaching the code below and some pictures---might have been easier to just move to a house.
Wemos Temperature Unit Code:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <Encoder.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
// OLED display setup
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// DHT sensor setup
#define DHTPIN 2 // GPIO 2, D4 on the Wemos D1 Mini
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// Rotary Encoder setup
#define ENCODER_PIN1 14 // GPIO 14, D5 on the Wemos
#define ENCODER_PIN2 12 // GPIO 12, D6 on the Wemos
Encoder myEnc(ENCODER_PIN1, ENCODER_PIN2);
// Wi-Fi credentials
const char* ssid = "SSID goes here";
const char* password = "Password goes here"; // not today hackers
// Variables for temperature
float currentTemp = 0.0;
int setTemp = 72; // Default Set Temperature in Fahrenheit
long oldPosition = -999; // Rotary encoder position
// Peer MAC Address for Wemos AC
uint8_t wemosACAddress[] = {x, x, x, x, x, x}; // MAC address of Wemos AC
void onDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
Serial.print("Delivery success status: ");
Serial.println(sendStatus == 0 ? "Success" : "Fail");
}
void setup() {
Serial.begin(115200);
// Start the DHT sensor
dht.begin();
// Initialize OLED display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
delay(1000);
// Initialize WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println(" Connected!");
// Initialize ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
esp_now_add_peer(wemosACAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
esp_now_register_send_cb(onDataSent);
}
void loop() {
// Read temperature from DHT11 (convert to Fahrenheit)
currentTemp = dht.readTemperature(true);
// Print temperature to Serial Monitor
if (!isnan(currentTemp)) {
Serial.print("Current Temperature: ");
Serial.print(currentTemp);
Serial.println(" F");
} else {
Serial.println("Error reading temperature!");
}
// Update set temperature using rotary encoder
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
setTemp = constrain(setTemp + (newPosition / 4), 50, 85); // Adjusting the setTemp with constraints between 50 and 85 Fahrenheit
myEnc.write(0); // Reset encoder reading
Serial.print("Set Temperature: ");
Serial.println(setTemp);
}
// Update OLED display
display.clearDisplay();
// Display Set Temperature (slightly larger)
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print("Set: ");
display.print(setTemp);
display.print(" F");
// Display Current Temperature (larger, without label)
display.setTextSize(3);
display.setCursor(0, 25);
display.print((int)currentTemp); // Remove decimals
display.print(" F");
// Draw a sun icon with rays next to the current temperature
int sunX = 110;
int sunY = 35;
int sunRadius = 5;
// Draw sun circle
display.fillCircle(sunX, sunY, sunRadius, SSD1306_WHITE);
// Draw sun rays
for (int i = 0; i < 360; i += 45) {
int rayLength = 10;
float angle = i * 3.14 / 180;
int x1 = sunX + cos(angle) * (sunRadius + 2);
int y1 = sunY + sin(angle) * (sunRadius + 2);
int x2 = sunX + cos(angle) * (sunRadius + rayLength);
int y2 = sunY + sin(angle) * (sunRadius + rayLength);
display.drawLine(x1, y1, x2, y2, SSD1306_WHITE);
}
display.display();
// Send signal to Wemos AC if the temperature crosses the threshold
if (!isnan(currentTemp)) {
if (currentTemp < setTemp) {
// Send command to Wemos AC to rotate servo to 170 degrees
char message[] = "OPEN";
esp_now_send(wemosACAddress, (uint8_t *)message, sizeof(message));
Serial.println("Sent command to OPEN AC");
} else if (currentTemp >= setTemp + 2) {
// Send command to Wemos AC to rotate servo back to original position
char message[] = "CLOSE";
esp_now_send(wemosACAddress, (uint8_t *)message, sizeof(message));
Serial.println("Sent command to CLOSE AC");
}
}
delay(500); // Update every 500 milliseconds
}
___________________________________________
Wemos Servo Motor Code:
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <Servo.h>
// Servo setup
#define SERVO_PIN 2 // GPIO 2, corresponding to D4 on the Wemos D1 Mini
Servo acServo;
// Minimum delay between servo commands (in milliseconds)
#define COMMAND_COOLDOWN 2000
unsigned long lastCommandTime = 0;
void onDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len) {
// Get the current time
unsigned long currentTime = millis();
// Check if enough time has passed since the last command
if (currentTime - lastCommandTime < COMMAND_COOLDOWN) {
Serial.println("Ignoring command: Cooldown period not finished");
return;
}
// Print MAC address of the sender
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.print("Received data from MAC: ");
Serial.println(macStr);
// Convert incoming data to string command
char command[len + 1];
strncpy(command, (char *)incomingData, len);
command[len] = '\0'; // Null-terminate the string
Serial.print("Received command: ");
Serial.println(command);
// Update the last command time to now
lastCommandTime = currentTime;
// Reattach the servo each time to make sure it is active
acServo.attach(SERVO_PIN);
// Process command
if (strcmp(command, "OPEN") == 0) {
// Rotate servo 170 degrees (closer to max range)
Serial.println("Executing command: OPEN - Moving servo to 170 degrees");
acServo.write(180);
delay(500); // Small delay to ensure stable signal
Serial.println("Servo set to 170 degrees");
} else if (strcmp(command, "CLOSE") == 0) {
// Rotate servo back to 0 degrees
Serial.println("Executing command: CLOSE - Moving servo to 0 degrees");
acServo.write(0);
delay(500); // Small delay to ensure stable signal
Serial.println("Servo set to 0 degrees");
} else {
Serial.println("Received an unrecognized command.");
}
// Detach the servo after use to minimize jitter or power draw
acServo.detach();
}
void setup() {
Serial.begin(115200);
Serial.println("Starting Wemos AC Setup...");
// Initialize Servo
Serial.println("Initializing Servo...");
acServo.attach(SERVO_PIN);
acServo.write(0); // Start at 0 degrees
Serial.println("Servo initialized at 0 degrees");
// Initialize WiFi in Station mode
Serial.println("Initializing WiFi...");
WiFi.mode(WIFI_STA);
Serial.println("WiFi initialized in station mode");
// Initialize ESP-NOW
Serial.println("Initializing ESP-NOW...");
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
Serial.println("ESP-NOW initialized successfully");
// Set up ESP-NOW to receive data
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
esp_now_register_recv_cb(onDataRecv);
Serial.println("ESP-NOW receiver callback registered");
}
void loop() {
// Nothing needed here, commands are received asynchronously
}
Comments