A Go library for controlling TP-Link Kasa smart home devices using the local protocol.
- Local Control: Communicates directly with devices on your network (no cloud required)
- Device Discovery: Automatic UDP broadcast discovery
- Full HS300 Support: Per-plug power monitoring for power strips
- Energy Monitoring: Read voltage, current, power consumption, and total energy
- Device Management: Control and monitor multiple devices simultaneously
- Clean API: Well-structured, idiomatic Go interfaces
- ✅ HS300 - 6-outlet power strip with per-plug power monitoring
- ✅ KP303 - 3-outlet power strip (on/off control)
- ✅ HS110 - Smart plug with energy monitoring
- ✅ HS105/HS103 - Basic smart plugs
- ✅ KP115 - Smart plug with energy monitoring
Most TP-Link Kasa devices using the local protocol should work.
go get github.com/scttfrdmn/kasapackage main
import (
"context"
"fmt"
"time"
"github.com/scttfrdmn/kasa"
)
func main() {
ctx := context.Background()
devices, err := kasa.DiscoverDevices(ctx, 5*time.Second)
if err != nil {
panic(err)
}
for _, dev := range devices {
fmt.Printf("Found: %s (%s) at %s\n", dev.Name, dev.Model, dev.IP)
}
}client := kasa.NewClient(10 * time.Second)
// Get system information
data, err := client.GetSysInfo("192.168.1.100", kasa.DefaultPort)
if err != nil {
panic(err)
}
sysInfo, err := kasa.ParseSysInfoResponse(data)
if err != nil {
panic(err)
}
fmt.Printf("Device: %s\n", sysInfo.System.GetSysInfo.Alias)
fmt.Printf("Model: %s\n", sysInfo.System.GetSysInfo.Model)// Get energy meter data
data, err := client.GetEnergyMeter("192.168.1.100", kasa.DefaultPort)
if err != nil {
panic(err)
}
energy, err := kasa.ParseEnergyMeterResponse(data)
if err != nil {
panic(err)
}
fmt.Printf("Voltage: %.1f V\n", energy.GetVoltage())
fmt.Printf("Current: %.2f A\n", energy.GetCurrent())
fmt.Printf("Power: %.1f W\n", energy.GetPower())
fmt.Printf("Total: %.2f kWh\n", energy.GetTotal())// Get per-plug energy data
plugID := "800636EE67F78B4ADB2452AECE8C2ACE24CB7BC400"
data, err := client.GetPlugEnergyMeter("192.168.1.100", kasa.DefaultPort, plugID)
if err != nil {
panic(err)
}
energy, err := kasa.ParseEnergyMeterResponse(data)
if err != nil {
panic(err)
}
fmt.Printf("Plug Power: %.1f W\n", energy.GetPower())manager := kasa.NewManager()
// Add devices
manager.AddDevice("192.168.1.100", kasa.DefaultPort, "Living Room Strip")
manager.AddDevice("192.168.1.101", kasa.DefaultPort, "Kitchen Plug")
// Start background polling
ctx := context.Background()
go manager.StartPolling(ctx, 3*time.Second)
// Wait a moment for first poll
time.Sleep(time.Second)
// Get device information
devices := manager.GetDevices()
for _, dev := range devices {
fmt.Printf("%s: %.1f W\n", dev.Name, dev.EnergyData.Power)
// Per-plug information for power strips
for _, plug := range dev.Plugs {
status := "OFF"
if plug.State {
status = "ON"
}
fmt.Printf(" Plug %d (%s): %s", plug.Index+1, plug.Name, status)
if plug.EnergyData != nil {
fmt.Printf(" - %.1f W", plug.EnergyData.Power)
}
fmt.Println()
}
}The repository includes several example applications:
A real-time terminal dashboard for monitoring your devices:
cd cmd/dashboard
go build
./dashboardFeatures:
- Auto-discovery or manual configuration
- Real-time power monitoring
- Per-plug status and consumption (HS300)
- Interactive TUI with device navigation
Scan your network for all Kasa devices:
cd examples/scan
go build
./scanInspect raw device responses:
cd examples/debug
go build
./debug 192.168.1.100The TP-Link Kasa protocol uses:
- Port: TCP/UDP 9999
- Encryption: Autokey XOR cipher (initialization key: 0xAB)
- Format: 4-byte big-endian length prefix + encrypted JSON payload
// System info (device details, plug states)
{"system":{"get_sysinfo":null}}
// Energy meter (whole device)
{"emeter":{"get_realtime":null}}
// Per-plug energy (HS300)
{"context":{"child_ids":["PLUG_ID"]},"emeter":{"get_realtime":{}}}
// Turn on/off
{"system":{"set_relay_state":{"state":1}}} // 1=on, 0=offRepresents a Kasa smart device with all state information.
type Device struct {
Name string
Model string
IP string
Port int
HardwareVer string
SoftwareVer string
DeviceID string
LastUpdate time.Time
Status DeviceStatus
Plugs []PlugStatus
EnergyData *EnergyData
}Status of an individual plug on a power strip.
type PlugStatus struct {
Index int
ID string
Name string
State bool // true = on, false = off
OnTime int // Seconds the plug has been on
EnergyData *EnergyData // Per-plug energy data (HS300)
}Real-time energy monitoring data.
type EnergyData struct {
Voltage float64 // Voltage in volts
Current float64 // Current in amps
Power float64 // Power in watts
Total float64 // Total energy consumed in kWh
}NewClient(timeout time.Duration) *Client- Create a new clientSendCommand(ip string, port int, command []byte) ([]byte, error)- Send raw commandGetSysInfo(ip string, port int) ([]byte, error)- Get system informationGetEnergyMeter(ip string, port int) ([]byte, error)- Get energy meter dataGetPlugEnergyMeter(ip string, port int, childID string) ([]byte, error)- Get per-plug energy
DiscoverDevices(ctx context.Context, timeout time.Duration) ([]DiscoveredDevice, error)- Discover devices on network
NewManager() *Manager- Create device managerAddDevice(ip string, port int, name string)- Add device to monitorRemoveDevice(ip string)- Remove device from monitoringGetDevices() []*Device- Get all monitored devicesStartPolling(ctx context.Context, interval time.Duration)- Start background polling
Encrypt(plaintext []byte) []byte- Encrypt using Kasa XOR cipherDecrypt(ciphertext []byte) []byte- Decrypt using Kasa XOR cipherBuildGetSysInfoCommand() []byte- Build sysinfo commandBuildGetEnergyMeterCommand() []byte- Build energy meter commandBuildGetPlugEnergyCommand(childID string) []byte- Build per-plug energy commandParseSysInfoResponse(data []byte) (*SysInfoResponse, error)- Parse sysinfo responseParseEnergyMeterResponse(data []byte) (*EnergyMeterResponse, error)- Parse energy response
kasa/
├── README.md # This file
├── go.mod # Go module definition
├── protocol.go # Protocol constants
├── encryption.go # XOR cipher implementation
├── command.go # Command builders
├── types.go # Data structures and response parsing
├── client.go # Low-level TCP client
├── manager.go # High-level device manager
├── discovery.go # UDP device discovery
├── cmd/
│ └── dashboard/ # Terminal dashboard application
└── examples/
├── scan/ # Network scanner
└── debug/ # Debug tool
Protocol implementation based on reverse engineering work by:
Apache License 2.0 - see LICENSE file for details.
Copyright 2026 Scott Friedman
Contributions welcome! Please feel free to submit a Pull Request.