Today I learned - You can track energy consumption of a Smart Plug

I recently bought one of these Tapo TPLink Smart Plugs. It is a cool smart plug that lets you remotely turn a plug on or off.

You plug another plug directly into it and then plug the Smart Plug into the wall.

Another cool thing it can do is show you energy consumption by day / week / month.

I decided I'd like to pull this information off the device and create some charts for myself with Python.

I found this unofficial API REST API that lets you do that. Here are the docs for that API.

I wrote a script using this that would pull in a config file for all the plugs in your house, and some Auth information for your TPLink account.

{
    "auth": {
      "email": "<EMAIL>",
      "password": "<PASSWORD>"
    },
    "devices": [
      {
        "name": "smart-plug",
        "device_type": "P110",
        "ip_addr": "192.168.1.208"
      }
    ]
}

Then I wrote a script that will iterate through each device and pull the hourly and daily information out and save some charts (shown below)

from tapo import ApiClient
from tapo.requests import EnergyDataInterval
import json
import asyncio
from datetime import datetime
import matplotlib.pyplot as plt

def load_config():
    with open("config.json", "r") as file:
        config = json.load(file)
    
    if not config:
        raise FileNotFoundError("Failed to load config")
    
    if "auth" not in config.keys():
        raise Exception("Failed to find auth in config file")
    
    return config

def get_quarter_start_month(today: datetime) -> int:
    return 3 * ((today.month - 1) // 3) + 1

async def load_device(email, password, device):
    
    if not email:
        raise Exception("Can't create client - missing email")
    if not password:
        raise Exception("Can't create client - missing password")
    if not device["ip_addr"]:
        raise Exception("Can't create client - missing device ip_addr")
    
    if device["device_type"] == "P110":
        client = ApiClient(email, password)
        device = await client.p110(device["ip_addr"])
        return device

def plot_daily(energy_data):
    days = list(range(1, len(energy_data.data) + 1))

    plt.figure(figsize=(10, 5))
    plt.plot(days, energy_data.data, marker='o', linestyle='-', color='b')
    plt.title('Daily Energy Usage')
    plt.xlabel('Day')
    plt.ylabel('Energy (kWh)')
    plt.grid(True)
    plt.savefig('daily.png')
    plt.close()

def plot_hourly(energy_data):
    days = list(range(1, len(energy_data.data) + 1))

    plt.figure(figsize=(10, 5))
    plt.plot(days, energy_data.data, marker='o', linestyle='-', color='b')
    plt.title('Hourly Energy Usage')
    plt.xlabel('Hour')
    plt.ylabel('Energy (kWh)')
    plt.grid(True)
    plt.savefig('hourly.png')
    plt.close()


async def main():
    config = load_config()
    email = config["auth"]["email"]
    password = config["auth"]["password"]
    for device in config["devices"]:
        client = await load_device(email=email, password=password, device=device)

        today = datetime.today()
        
        energy_data_daily = await client.get_energy_data(
            EnergyDataInterval.Daily,
            datetime(today.year, get_quarter_start_month(today), 1),
        )

        energy_data_hourly = await client.get_energy_data(
            EnergyDataInterval.Hourly,
            today
        )

        plot_daily(energy_data=energy_data_daily)
        plot_hourly(energy_data=energy_data_hourly)

    
if __name__ == "__main__":
    asyncio.run(main())

Run that and it will generate charts like the following

I am going to buy a few more of these plugs and keep historical data of the usage of individual devices, especially as I am building a powerful server in the coming weeks, I want to test different power configurations for the GPUs this data will be very valuable.