Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Nickson Kiprotich
Published © GPL3+

UNIHIKER Smart Home Terminal

A Centralized Smart-Home System for Controlling and Monitoring IoT Devices

BeginnerWork in progress2 hours1,280
UNIHIKER Smart Home Terminal

Things used in this project

Story

Read more

Schematics

Unihiker

Code

UNIHIKER PYTHON CODE

Python
import tkinter as tk
import socket
import json
import threading
import time

class Room:
    def __init__(self, name, controls, ip_address):
        self.name = name
        self.temperature = 20
        self.humidity = 50
        self.appliances = {control: False for control in controls}
        self.ip_address = ip_address

class Dashboard:
    def __init__(self, master):
        self.master = master
        master.title("SMART HOME")
        master.configure(bg="#2c3e50")
        
        self.rooms = [
            Room("Living Room", ["Light", "TV", "AC", "Fan"], "192.168.137.57"),
            Room("Bedroom", ["Light", "Fan", "Heater"], "192.168.1.102"),
            Room("Kitchen", ["Light", "Oven", "Fridge"], "192.168.1.103"),
            Room("Bathroom", ["Light"], "192.168.1.104")
        ]
        self.current_room = None
        self.create_main_dashboard()
        
        # Start a thread for periodic updates
        self.update_thread = threading.Thread(target=self.periodic_update, daemon=True)
        self.update_thread.start()

    def create_main_dashboard(self):
        for widget in self.master.winfo_children():
            widget.destroy()
        tk.Label(self.master, text="SMART HOME", font=("Arial", 20, "bold"), bg="#2c3e50", fg="#ecf0f1").pack(pady=10)
        button_styles = {
            "Living Room": "#e74c3c", "Bedroom": "#3498db",
            "Kitchen": "#2ecc71", "Bathroom": "#f1c40f",
        }
        for room in self.rooms:
            tk.Button(
                self.master, 
                text=room.name, 
                command=lambda r=room: self.show_room_dashboard(r),
                font=("Arial", 13),
                bg=button_styles[room.name],
                fg="#ffffff", 
                width=18, height=2,
                relief=tk.FLAT,
            ).pack(pady=5)

    def show_room_dashboard(self, room):
        self.current_room = room
        for widget in self.master.winfo_children():
            widget.destroy()
        tk.Label(self.master, text=room.name, font=("Arial", 18, "bold"), bg="#2c3e50", fg="#ecf0f1").pack(pady=10)
        
        # Sensor display
        sensor_frame = tk.Frame(self.master, bg="#34495e", bd=2, relief=tk.RAISED)
        sensor_frame.pack(fill=tk.X, padx=10, pady=5)
        self.temp_label = tk.Label(sensor_frame, text=f"Temp: {room.temperature}C", font=("Arial", 13), bg="#34495e", fg="#ffffff")
        self.temp_label.pack(side=tk.LEFT, expand=True, pady=10)
        self.humid_label = tk.Label(sensor_frame, text=f"Hum: {room.humidity}%", font=("Arial", 13), bg="#34495e", fg="#ffffff")
        self.humid_label.pack(side=tk.RIGHT, expand=True, pady=10)
        
        # Controls
        control_frame = tk.Frame(self.master, bg="#2c3e50")
        control_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        for i, (appliance, status) in enumerate(room.appliances.items()):
            button = tk.Button(
                control_frame,
                text=f"{appliance}: {'On' if status else 'Off'}",
                command=lambda a=appliance: self.toggle_appliance(a),
                font=("Arial", 12),
                bg="#2ecc71" if status else "#e74c3c",
                fg="#ffffff",
                width=15, height=2,
                relief=tk.FLAT,
            )
            button.grid(row=i//2, column=i%2, pady=5, padx=5, sticky="nsew")
        control_frame.grid_columnconfigure(0, weight=1)
        control_frame.grid_columnconfigure(1, weight=1)
        
        tk.Button(
            self.master, 
            text="Back to Main", 
            command=self.create_main_dashboard, 
            font=("Arial", 12), 
            bg="#7f8c8d", 
            fg="#ffffff",
            width=20, height=2,
            relief=tk.FLAT,
        ).pack(pady=10)

    def toggle_appliance(self, appliance):
        if self.current_room:
            new_status = not self.current_room.appliances[appliance]
            self.current_room.appliances[appliance] = new_status
            self.send_command(self.current_room.ip_address, appliance, new_status)
            self.show_room_dashboard(self.current_room)  # Refresh the room dashboard

    def send_command(self, ip_address, appliance, status):
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.connect((ip_address, 8080))
                command = json.dumps({"command": "set", "appliance": appliance, "status": status})
                s.sendall(command.encode())
                response = s.recv(1024).decode()
                print(f"Response from {ip_address}: {response}")
        except Exception as e:
            print(f"Error sending command to {ip_address}: {e}")

    def get_room_data(self, ip_address):
        try:
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
                s.connect((ip_address, 8080))
                command = json.dumps({"command": "get"})
                s.sendall(command.encode())
                response = s.recv(1024).decode()
                return json.loads(response)
        except Exception as e:
            print(f"Error getting data from {ip_address}: {e}")
            return None

    def update_room_data(self, room, data):
        if data:
            room.temperature = data.get('temperature', room.temperature)
            room.humidity = data.get('humidity', room.humidity)
            room.appliances.update(data.get('appliances', {}))

    def periodic_update(self):
        while True:
            for room in self.rooms:
                data = self.get_room_data(room.ip_address)
                self.update_room_data(room, data)
            
            if self.current_room:
                self.master.after(0, self.update_current_room_display)
            
            time.sleep(5)  # Update every 5 seconds

    def update_current_room_display(self):
        if self.current_room:
            self.temp_label.config(text=f"Temp: {self.current_room.temperature}C")
            self.humid_label.config(text=f"Hum: {self.current_room.humidity}%")
            self.show_room_dashboard(self.current_room)

def main():
    root = tk.Tk()
    root.geometry("240x320")
    dashboard = Dashboard(root)
    root.mainloop()

if __name__ == "__main__":
    main()

ESP32 CODE

Arduino
#include <WiFi.h>
#include <ArduinoJson.h>
#include <DHT.h>

const char* ssid = "*******";
const char* password = "********";

#define DHTPIN D1     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11   // DHT 11

DHT dht(DHTPIN, DHTTYPE);

// Define pins for appliances
const int LIGHT_PIN = D6;
const int TV_PIN = D5;
const int FAN_PIN = D4;
const int AC_PIN = D3;

WiFiServer server(8080);

void setup() {
  Serial.begin(115200);
  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // Initialize DHT sensor
  dht.begin();

  // Set up appliance control pins
  pinMode(LIGHT_PIN, OUTPUT);
  pinMode(TV_PIN, OUTPUT);
  pinMode(FAN_PIN, OUTPUT);
  pinMode(AC_PIN, OUTPUT);

  // Start the server
  server.begin();
}

void loop() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New client connected");
    String request = client.readStringUntil('\r');
    client.flush();

    StaticJsonDocument<200> doc;
    DeserializationError error = deserializeJson(doc, request);

    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.f_str());
      client.stop();
      return;
    }

    String command = doc["command"];

    if (command == "get") {
      // float temperature = dht.readTemperature();
      // float humidity = dht.readHumidity();
      float temperature = 25;
      float humidity = 72;

      StaticJsonDocument<200> response;
      // response["temperature"] = isnan(temperature) ? nullptr : temperature;
      // response["humidity"] = isnan(humidity) ? nullptr : humidity;

      response["temperature"] = temperature;
      response["humidity"] = humidity;


      response["appliances"]["Light"] = digitalRead(LIGHT_PIN);
      response["appliances"]["TV"] = digitalRead(TV_PIN);
      response["appliances"]["Fan"] = digitalRead(FAN_PIN);
      response["appliances"]["AC"] = digitalRead(AC_PIN);

      String jsonResponse;
      serializeJson(response, jsonResponse);
      client.println(jsonResponse);
    }
    else if (command == "set") {
      String appliance = doc["appliance"];
      bool status = doc["status"];

      int pin = -1;
      if (appliance == "Light") pin = LIGHT_PIN;
      else if (appliance == "TV") pin = TV_PIN;
      else if (appliance == "Fan") pin = FAN_PIN;
      else if (appliance == "AC") pin = AC_PIN;

      if (pin != -1) {
        digitalWrite(pin, status ? HIGH : LOW);
        client.println("{\"status\":\"success\"}");
      }
      else {
        client.println("{\"status\":\"error\",\"message\":\"Invalid appliance\"}");
      }
    }
    else {
      client.println("{\"status\":\"error\",\"message\":\"Invalid command\"}");
    }

    client.stop();
    Serial.println("Client disconnected");
  }
}

UNIHIKER PYTHON CODE

Clone the repo

Credits

Nickson Kiprotich
8 projects • 20 followers
Iot, Robotics & TinyML Enthusiast
Contact

Comments

Please log in or sign up to comment.