Building Smart Home Applications with Go

Grab your keyboard and let’s get hands-on!

Our goal is to create an application that can control smart lights via an HTTP interface. The main features of this application include:

  1. Starting an HTTP server.
  2. Receiving requests to control the light’s state (on/off).
  3. Returning the current state of the light.

In practical applications, such functionality can be extended to control multiple devices, such as air conditioners, curtains, etc. Let’s start with the most basic light control functionality.

In Go, building an HTTP server is very simple. We can use the net/http package from the standard library to implement it quickly.

go复制

package main

import (
	"fmt"
	"net/http"
)

func main() {
	// Set up a simple route
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Welcome to the Smart Home Application!")
	})

	// Start the HTTP server
	fmt.Println("Server starting, listening on port 8080")
	http.ListenAndServe("8080", nil)
}

Expected Result: After running the code, open your browser and visit <http://localhost:8080>, and you will see the prompt “Welcome to the Smart Home Application!”.

Tip: http.ListenAndServe will block the execution of the current program, so ensure your code logic is written before it or handle it with Goroutine.

Now, let’s add the functionality for the smart light. We will use a boolean variable lightOn to simulate the state of the light and control it via HTTP requests.

go复制

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sync"
)

var (
	lightOn bool       // Simulate the state of the light
	mu      sync.Mutex // Ensure thread safety of the state
)

// Control the state of the light
func controlLightHandler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	defer mu.Unlock()

	// Parse request parameters
	action := r.URL.Query().Get("action")
	if action == "on" {
		lightOn = true
		fmt.Fprintln(w, "The light has been turned on!")
	} else if action == "off" {
		lightOn = false
		fmt.Fprintln(w, "The light has been turned off!")
	} else {
		http.Error(w, "Invalid action parameter, please use 'on' or 'off'", http.StatusBadRequest)
	}
}

// Get the status of the light
func getLightStatusHandler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	defer mu.Unlock()

	// Construct JSON response
	status := map[string]interface{}{
		"lightOn": lightOn,
	}
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(status)
}

func main() {
	// Register routes
	http.HandleFunc("/control", controlLightHandler)
	http.HandleFunc("/status", getLightStatusHandler)

	// Start the HTTP server
	fmt.Println("Smart light server starting, listening on port 8080")
	http.ListenAndServe("8080", nil)
}
  1. Light Control Interface: Use /control?action=on to turn on the light, /control?action=off to turn off the light.
  2. Get Light Status: Access the /status interface to return the light’s status, formatted as {"lightOn": true/false}.
  3. Thread Safety: Use sync.Mutex to ensure that the lightOn state does not encounter data races during multi-threaded access.

Expected Result:

  • Access http://localhost:8080/control?action=on, returns “The light has been turned on!”.
  • Access http://localhost:8080/control?action=off, returns “The light has been turned off!”.
  • Access http://localhost:8080/status, returns the light’s JSON status, for example {"lightOn": true}.
  1. Communicate with Hardware: Send commands to actual smart lights via serial ports, Bluetooth, or Zigbee protocols.
  2. Integrate with Cloud Services: Sync statuses to the cloud for easy control of devices via a mobile app.
  3. Multi-Device Support: Use a device list to manage multiple smart home devices.

go复制

type Device struct {
	Name   string `json:"name"`
	Status bool   `json:"status"`
}

var devices = map[string]*Device{
	"light": {Name: "Smart Light", Status: false},
	"fan":   {Name: "Fan", Status: false},
}

func controlDeviceHandler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	defer mu.Unlock()

	deviceName := r.URL.Query().Get("device")
	action := r.URL.Query().Get("action")

	device, exists := devices[deviceName]
	if !exists {
		http.Error(w, "Device does not exist", http.StatusNotFound)
		return
	}

	if action == "on" {
		device.Status = true
		fmt.Fprintf(w, "%s has been turned on!", device.Name)
	} else if action == "off" {
		device.Status = false
		fmt.Fprintf(w, "%s has been turned off!", device.Name)
	} else {
		http.Error(w, "Invalid action parameter", http.StatusBadRequest)
	}
}

func getDevicesStatusHandler(w http.ResponseWriter, r *http.Request) {
	mu.Lock()
	defer mu.Unlock()

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(devices)
}
  1. Start an HTTP server.
  2. Implement control and query functions for the smart light’s state.
  3. Expand the implementation ideas for multi-device support.

Exercises:

  1. Add a smart air conditioning device to the application that supports setting the temperature.
  2. Optimize the code to store device statuses in a file, allowing the program to restore status after a restart.
  3. Add timestamps for each device’s switch actions, returning the last operation time.

Get hands-on! I believe that through continuous practice, you will become more familiar with Go language development ideas.

()

Leave a Comment