Monthly Archives: April 2024

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

Using WSL as regular Linux host on same network with 10 gigabit and NFS

What if you could use WSL as a regular Linux host on same network? For developers this would be big right? What about app developers that test apps on Windows, Linux, Android, Web etc. You could do it all from one place, and have convenience of mounting your NAS on your WSL machine with NFS to backup your WSL files you been working on, whether you working with flutter, flet, or whatever your preference is. Or maybe just you like to ssh into your WSL machine to run Unix commands on your windows desktop from your laptop etc…

Alright let’s assume we are a developer and not a hacker, we will want latest Ubuntu LTS release(as developers always test with this distro more than anything else), but feel free to install Kali instead if that’s your thing…

Let’s do it, what we will accomplish here is install Ubuntu-22.04 WLS2, we will start this instance when we login to windows in background so we can ssh into it, we will also mount NFS directory from our NAS so you can just copy anything you want to backup to it easily. So let’s say I do a lot of work in my /home/dan directory, I will mount NAS to /data directory and anytime I want to backup anything, I’ll copy it there. We could go more advanced and just mount our /home/dan directory from a FreeBSD zfs pool and revert snapshots to anytime we want 🙂 , but we will keep it simple…

On security end of things, you should only NFS mount anything on WSL that you normally map with samba from your NAS. If ever get malicious code on your windows computer, you don’t want to open your whole NAS to it. Worst case scenario you loose 2 days of your life reinstalling windows again with backups from private NAS backups and rolling back snapshots on your ZFS system.

Notes on backups

I personally have a 2nd server I leave offline and only bring it online occasionally to backup first NAS, blame SSD corporate greed, spinning drives cheaper but can only spin 3-6 years before they fail, so this ensures I don’t have 2 drives fail at same time on each if they don’t rust first lol. NVME’s are still only mainly used as OS drives, quite sad really. When I used to work for fortune 500 companies they used to backup regularly to tape drives, and every few months send that backup offsite as well. If their colocation caught fire, they didn’t loose everything this way. So while it’s a good idea to do an onsite solution like I have, it’s also a good idea to rent a VPS/dedicated/colocated server and backup stuff there occasionally as well.

In the 90s I use used to program in C etc, I kicked my PC to many times and the drive failed, lost a whole year worth of C programming libraries I made, never touched it again, went into perl/php/python after that. Another example, one backup server one time I forgot to create ZFS snapshots on it, so one day when first server had drive fail, I replaced it with a blank slate, the backup server then rsync’d an empty drive one night before I got to it and lost almost everything. So moral of story is, a) snapshots b) 2nd NAS to backup first c) copy things you want to keep offsite in case of a fire. You decide, but I know how long apps take to develop when your new at it, I’d hate to see you give up on a project because you didn’t use github or a VPS.

Notes on FreeBSD

I can’t stress enough how your servers should be running FreeBSD as main host. By utilizing BHYVE virtualization your virtual hosts will be rock solid, and the ports collection is enormous, it is essentially a sys admin’s dream. See my previous posts on running FreeBSD with vm-byve. Not just the fact you have more packages available to you than any other OS on the planet, the main reason is ZFS. Linus Torvalds already stated he won’t allow ZFS in Linux kernel, and always people hacking it in there on their Linux distros is a real waste of time, for backing up data, there is no better OS. At home my FreeBSD servers do everything, wireguard, DNS, DHCPD, backups, snapshots, virtual hosts, 10 gigabit fiber, you name it, it’s something you can’t do with prebuilt solutions like FreeNAS, proxmox, etc taking the control away from you. Take control back and you won’t regret it. I even demonstrated how to run home assistant with it and not needing to buy a raspberry pie with inferior hardware 🙂

Getting started with WSL prerequisites

First thing we need is a bridge, this will allow us to be on same network as our regular LAN for dhcpd etc… If you don’t have 10 gigabit skip #2, replace your username dan with whatever your C:\Users\$username is…

1) create a bridge:
search for hyper-v, should see something to enable you to add that addons to windows, add then restart PC.
Now open Hyper-V manager, select <your PC name>, and select "virtual switch manager"
Now create a new virtual switch that is "external" and call it "WSL Bridge"
Check it has our external network 10GB card etc.
2) enable jumbo packet on new virtual switch
control panel -> Network and Sharing Center -> "vEthernet (WSL Bridge)" -> properties -> configure -> advanced
set Jumbo Packet to "9014"

Now we need to edit the main wsl file to use this bridge, again replace dan with your username:

3) In WSL:
nano /mnt/c/Users/dan/.wslconfig OR just do it from your C:\home\Users\dan\.wslconfig windows file
ADD:
[wsl2]
vmIdleTimeout=-1
networkingMode = bridged
vmSwitch = "WSL Bridge"
ipv6=true

PLEASE NOTE: could not get X11 forwarding working without ipv6 enabled
the reason is you would have to change in /etc/ssh/sshd_config "AddressFamily any" to "AddressFamily inet"

Let’s actually install WSL

wsl --list --online
wsl --install -d Ubuntu-22.04

Now let’s create a .bat file that runs when we login to start WSL automatically, in your C:\Users\$USER directory create a file called “WSL_start.bat” and let’s add to it:

@ECHO OFF
:: Start WSL in backgound
TITLE Starting WSL

:: Section 1: Starting WSL in background
set OS=Ubuntu-22.04
ECHO ==========================
ECHO Starting WSL %OS% in background, please wait...
ECHO ============================

wsl -d %OS% --exec dbus-launch true

Close the file remembering to replace OS= with whatever distribution you want to start. You may say why not just use that one wsl line to do it instead, well when you reboot your PC and login for first time, what you would have is just a blank terminal screen executing something and you would have no idea what it is, this way it is informative, and you always know what it is, especially if you don’t have a superfast computer PCIE 5 PC, I’m on PCIE 4, and it’s around seconds.

Now let’s add that .bat file to “Task Scheduler”. Search for it and open it.

Go to “create task”. In “General” make sure “Run only when user is logged on” is checked. In “Triggers” select “Specific User” should be yourself. And on “Begin the task” select “At log on”. In “Actions” click “browse” and point to .bat file we created.

And that’s it we have a task created to start our WSL anytime we login, perfect.

Let’s start WSL

Open powershell and just type WSL and hit <tab> should autocomplete for you and hit enter:

PS C:\Users\dan> .\WSL_start.bat
==========================
Starting WSL Ubuntu-22.04 in background, please wait...
============================
PS C:\Users\dan>

Great now just login with “wsl” or “bash”. You can now check with “ifconfig -a” or “ip a” that your on same subnet as your regular LAN.

sudo su
apt install openssh-server
apt install  nfs-common
systemctl enable --now ssh

You should now be able to login with ssh, good to go. Go ahead and restart WSL and make sure everything working alright:
wsl --shutdown
.\WSL_start.bat
wsl
nano /etc/wsl.conf
#ADD following:
[network]
hostname = wsl
generateHosts = false

What we are doing here is setting our hostname and saying don’t overwrite /etc/hosts, that way you can add your IP to it etc without it getting overwritten. There is another option you can add to not overwrite /etc/resolv.conf, personally I feed it info with my DHCPD server so I like leaving if but it is “generateResolvConf = false”. If you set this option you need to restart WSL and it will completely nuke /etc/resolv.conf first time, so best to make a copy before rebooting then copy it back. Doing this however is only reliable way then to use hostnames in your /etc/fstab instead of IP address. Personally I feed the host it’s static IP address, MTU, DNS etc with my DHCPD server using it’s mac address so it’s good for me, if you want an example from my dhcpd.conf on FreeBSD I have following with isc-dhcpd currently for WSL:

subnet 192.168.0.0 netmask 255.255.255.0 {
       default-lease-time 259200;
       max-lease-time 432000;
       option broadcast-address 192.168.0.255;
       option domain-name "sunsaturn.com";
       option routers 192.168.0.1;
       range 192.168.0.150 192.168.0.200;
       option domain-name-servers 192.168.0.1, 8.8.8.8;
}

host wsl {
  hardware ethernet 5e:bb:f6:9e:ee:fa;
  fixed-address 192.168.0.19;
  option interface-mtu 9000;
}

This is a more convenient way to do it, that way you control WSL and everything on your network from one file. Obviously remove MTU line if you don't have 10 gigabit :) If you want to get more fancy, also edit your /etc/hosts , and also your reverse DNS on bind and add it as well, but for most part this will suffice. I'm generally lazy editing bind reverse file, dhcpd.conf and /etc/hosts on main host is fine.

This is what my /etc/hosts file looks like on wsl:
::1             localhost localhost.sunsaturn.com
127.0.0.1       localhost localhost.sunsaturn.com
192.168.0.19    wsl

Now let’s setup NFS, please note with NFS use IP address and not a hostname, only reliable way to use hostnames with NFS in /etc/fstab is if “generateResolvConf = false”, if that is something you really want then this is how I would do it:

cp /etc/resolv.conf /etc/resolv.conf.old
wsl --shutdown (windows)
wsl -d Ubuntu-22.04 --exec dbus-launch true (windows)
wsl
cp /etc/resolv.conf.old /etc/resolv.conf; pico /etc/resolv.conf

But I don’t, just here for reference.

NFS setup:

Add to /etc/fstab your mount, on your NAS make sure to allow IP etc in /etc/exports and restart mountd so wsl can access it then:

mkdir /data
pico /etc/fstab
#ADD following:
192.168.0.1:/data/yourfolder /data nfs vers=4,auto,noatime,nolock,tcp 0 0

Use your NAS IP and folder, but that it, now try it out:

mount /data

If everything went alright and you can see your files “ls -al /data”, your good to reboot and check NFS mount mounts on startup:

wls --shutdown
.\WSL_start.bat
wsl

And that’s it, you have NFS.

Final Thoughts

Microsoft should be adding ways to start WSL headless for us, also a way to access serial console. This however should get you going, until next time…..

SunSaturn