Category Archives: kasa

Using Home Assistant Kasa Matter Plugs and a Victron MPPT VEDirect cable to deplete your batteries for next day — Updated Version

In my last version I used home assistant to connect to KASA matter plugs, I have found nothing but problems with matter, especially kp125M plugs, that use matter. One day I was turning on and off grid breakers and then I had to delete devices from google and home assistant because they could not connect using matter anymore! In this version we will use non-matter KASA smart plugs and skip home assistant. You can review what we did before here: https://blog.sunsaturn.com/freebsd/using-home-assistant-kasa-matter-plugs-and-a-victron-mppt-vedirect-cable-to-deplete-your-batteries-for-next-day/

In this version since we used 2 different scripts accessing a lot of same functions, makes no sense to keep it that way, so let’s stick our functions for KASA plugs and Victron’s VEDIRECT in a separate class file, and remake our 2 scripts for our cronjob.

Let’s start by creating a file called victronclass.py to hold our 2 functions, and add following to it:

import vedirect
from kasa import SmartPlug

class VictronApp:
    def __init__(self):
        pass

    async def victron(self, serial_port, serial_baud):
        try:
            device = vedirect.VEDirect(serial_port, serial_baud)
        except Exception as e:
            print(f"VICTRON [FAIL] : Read bad data: {e}")
            return False
        try:
            float(device.battery_volts)
        except Exception as e:
            print(f"VICTRON [FAIL] : Return type was not a float: {e}")
            return False
        if not device.battery_volts > 0:
            print(f"VICTRON [FAIL] : Voltage not greater than 0!")
            return False
        print(f"VICTRON [SUCCESS] : Voltage is {device.battery_volts}")
        return device.battery_volts


    # Usage: status = await kasa_plug(IPADDRESS, "on/off/check")
    # Returns True if plug turned on or off or if "check" is used returns True if plug is on
    async def kasa_plug(self, ip, cmd):
        p = SmartPlug(ip)
        try:
            await p.update()
            if cmd == "check":
                if p.is_on:
                    print("KASA [CHECK] : Plug is on")
                    return True
                else:
                    print("KASA [CHECK] : Plug is off")
                    return False
        except Exception as e:
            print(f"KASA [FAIL] : Exception received connecting: {e}")
            return False
        if cmd == "on":
            if p.is_on:
                print("KASA [SUCCESS] : Plug already on doing nothing")
                return True
            else:
                try:
                    await p.turn_on()
                    await p.update()
                    if p.is_on:
                        print("KASA [SUCCESS] : Turned Plug on")
                    else:
                        print("KASA [FAIL] : Plug still off after turning it on")
                    return p.is_on
                except Exception as e:
                    print(f"KASA [FAIL] : Exception Received Turning on Plug: {e}")
                    return False
        elif cmd == "off":
            if p.is_off:
                print("KASA [SUCCESS] : Plug already off doing nothing")
                return True
            else:
                try:
                    await p.turn_off()
                    await p.update()
                    if p.is_off:
                        print("KASA [SUCCESS] : Turned Plug off")
                    else:
                        print("KASA [FAIL] : Plug still on after turning it off")
                    return p.is_off
                except Exception as e:
                    print(f"KASA [FAIL] : Exception Received Turning off Plug: {e}")
                    return False
        else:
            print("KASA [FAIL] : INVALID ARGUMENT: use [on] [off] or [check]")
            return False

We created 1 class to hold both our KASA and victron vedirect functions, that way we can reuse these in our 2 main files. Let’s create our first main file for our cronjob and call it victron.py:

import asyncio
from victronclass import VictronApp

async def main():
    # Config START
    # VICTRON
    # trying 25.9(35% spring getting 4KWh per day atm)
    voltage_max = 25.9          # we don't want voltage higher than this for morning solar charging--leaving it at 50% each night
    # https://batteryfinds.com/lifepo4-voltage-chart-3-2v-12v-24v-48v/
    serial_port = '/dev/cuaU0'  # serial_port for VEDIRECT, on linux try "setserial -g /dev/ttyUSB[01]" to find your serial port
    serial_baud = '19200'       # serial baud rate, 19200 seems recommended setting from Victron
    # KASA PLUG
    # kasa_ip = '192.168.0.x'    # Ip address of your Kasa plug
    kasa_ip = 'grid_plug'       # Ip address or /etc/hosts name of your Kasa plug
    # Config END

    v = VictronApp()
    # check voltage of battery
    volts = await v.victron(serial_port, serial_baud)  
    if not volts:
        print(f"ERROR: no volts, exiting program....")
        exit(1)
    kasa = await v.kasa_plug(ip=kasa_ip, cmd="check")

    if kasa:  # if plug is on
        # plug is on, check it we need to turn it off
        if volts > voltage_max:
            print(f"Voltage is greater than {voltage_max} Turning off Grid Plug")
            await v.kasa_plug(ip=kasa_ip, cmd="off")
        else:
            print(f"Grid Plug is on and voltage less than {voltage_max} DOING NOTHING")
    else:
        # plug is off, check it we need to turn it on
        if volts < voltage_max:
            print(f"Voltage is less than {voltage_max} Turning on Grid Plug")
            await v.kasa_plug(ip=kasa_ip, cmd="on")
        else:
            print(f"Grid Plug is off and voltage greater than {voltage_max} DOING NOTHING")

asyncio.run(main())

Now you can add this to cron as follows:

*/10 23 * * * (/root/cronjobs/victron.py) > /dev/null 2>&1
*/10 0-6 * * * (/root/cronjobs/victron.py) > /dev/null 2>&1

This should allow you to depleted your batteries between 11pm and 6:50am each day.

Now let’s create our program to turn on the grid KASA plug no matter what at 7am, let’s call it grid_on.py:

import asyncio
from victronclass import VictronApp

async def main():
    # Config START
    # kasa_ip = '192.168.0.x'    # Ip address of your Kasa plug
    kasa_ip = 'grid_plug'       # Ip address or /etc/hosts name of your Kasa plug

    # Config END

    v = VictronApp()
    kasa = await v.kasa_plug(ip=kasa_ip, cmd="on")

asyncio.run(main())

and add that to your crontab as follows:

0 7 * * * (/root/cronjobs/grid_on.py) > /dev/null 2>&1

Great your all set with new improved version not using home assistant for KASA anymore. After reading up on matter protocol I am not to fond of it. Not only does it use IPV6, it takes a IPV4 address on your home network if it becomes a border router. Most devices try to become a border router, in fact different companies fight over fact they should become it, then you got all these devices that are border routers.

So to make more of a headache for you , now you have to track those down and deal with them, whether you VLAN them off or just block them completely on your firewall.

I think what is safer is just have 1 hub communicating with a bunch of zigbee devices, at least zigbee devices don’t suddenly attempt to become border routers on your network and do as they please. Like phillip hues lights for instance, you just have one hub to deal with if it’s misbehaving in anyway, not have to deal with every single light trying to become a border router lol. For smart plugs you definitely want full control at all times with a definite IP address. Things like light bulbs should never be matter devices attempting to become border routers. If someone is going to hack your home network , they shouldn’t be able to plant a backdoor on your light bulb that became a border router, they should need to be in range, not in China!

Ultimate security is keep everything zigbee etc, and use your own server to control all the zigbee devices on home assistant, then you don’t even have to worry about a phillips hue hub etc doing bad things on your network. Or if your crazy security conscious I guess look for a smart plug that is zigbee/bluetooth etc controllable.

So probably your best bet with KASA is their kp125 without the “M” on the end. This way you get energy stats as well turn plugs on and off as you please. Other versions like their ep25 etc stay far away from, if you loose internet at your house, they require authentication to cloud to use them. WHY ON EARTH? No idea, great right, internet goes out and now you lost control over your devices! Unreal.

I mean this is whole reason people use Home Assistant etc in first place. If internet goes out, telling google to turn on a simple light is replied with, “Sorry I don’t care about you anymore your internet is down blah blah”….. let’s hope it’s not someone’s pacemaker one day!

As for more revisions to this program, if I get my hands on a Cerbo GX one day, I’ll probably update for that using TCP instead of serial for vedirect. Or I may update it to be just one long running program at some point that accommodates for winter/spring/summer/fall, as well as maybe weather conditions. I mean you can get like 4KW a day on 4 panels or more when sun in shining but in winter and cloudy days you get almost nothing, so after I get a year’s history of my solar I’ll have a better idea how to proceed.

Keep in mind you could always use a hybrid inverter for switching, although I don’t think it would support depleting your batteries to a certain voltage at night lol. Also honestly they all suck, their switching times are horrendous, like 10-20ms, that would knock out my old servers, and any old electronics instantly. Better is a straight up inverter and use a real PDU like a Tripplite on ebay. You can get them fairly cheap these days, and you get sub 2ms switching times, then your golden…

Till next time…

SunSaturn