Start a new topic

Off grid solar charging python script

Aloha from  Hawai'i :)  I have been searching this forum to see if anyone has posted this before, and it looks people have but didn't find a solution.


I have an off grid solar setup that I use to charge the 4 EV that our household has.  I use the Open EVSE and a Shelly UNI to modulate the EV charging rate.  I do this thru a python script.  The function of the script is to monitor the voltage of the battery connected to my solar inverter.  When the battery is full, the charge of the EV is started.  After starting the charge the script attempts to maintain a set voltage thru charge rate adjustments.  If the voltage falls below a set threshold then charging is ended until it rises above the start charge setpoint.  


I'm sure there is plenty of room for improvement and maybe an easier way to accomplish this task, however I have hopes this helps those that are looking and maybe starts a discussion for and easier way :)


The Shelly uni is only $12, it can do up to a 30V without any extras, much more with the addition of a voltage divider.  https://www.shelly.com/en-us/products/shop/shelly-uni-us


This is the script I wrote, my coding is not good and I have never had any training whatsoever in code :(


import requests

import traceback

import time

# Setpoint voltage for maintaining charging

setpoint_voltage = XX.X # Define the setpoint voltage

# Voltage at which charging should start

start_voltage = XX.X # Define the start voltage

# Voltage at which charging should stop

stop_voltage = XX.X # Define the stop voltage

# Minimum and maximum charge rates in amps

min_current = XX # Define the minimum charge rate

max_current = XX # Define the maximum charge rate

# Maximum number of retries

max_retries = 10

# Shelly device API URL

shelly_api_url = "http://192.168.1.XXX/status"

shelly_username = "XXXXXXXXX"

shelly_password = "XXXXXXXXXX"

# OpenEVSE API URL

openevse_api_url = "http://openevse-XXXX.local"

openevse_client_id = 1 # Define the OpenEVSE client ID

# Function to get current voltage from Shelly device

def get_voltage():

    retries = 0

    while retries < max_retries:

        try:

            response = requests.get(shelly_api_url, auth=(shelly_username, shelly_password))

            if response.status_code == 200:

                data = response.json()

                adc_voltage = data.get("adcs", [])[0].get("voltage", None)

                if adc_voltage is not None:

                    return adc_voltage

                else:

                    print("ADC voltage data not found in response")

                    return None

            else:

                print("Failed to fetch voltage data from Shelly device. Status code:", response.status_code)

                return None

        except requests.RequestException as e:

            print("Request failed:", e)

            retries += 1

            print("Retrying...")

            time.sleep(5) # Wait before retrying

    print("Max retries reached. Could not fetch voltage data.")

    return None

# Function to control OpenEVSE charging based on ADC voltage

def control_charging():

    charge_current = 0 # Start with no charging

    charging_started = False # Flag to track if charging was initiated

    voltage_below_stop = False # Flag to track if voltage fell below stop voltage after charging started

    manual_start = False # Flag to track manual start

    # Manual start option (runs once at the beginning)

    manual_start_input = input("Do you want to start charging manually? (yes/no): ").strip().lower()

    if manual_start_input == "yes":

        charging_started = True

        manual_start = True

        print("Charging started manually.")

    else:

        manual_start = False

    while True:

        voltage = get_voltage()

        if voltage is not None:

            print("Current voltage:", voltage)

            # Start charging when voltage exceeds start voltage or manually started

            if (voltage >= start_voltage and not charging_started) or manual_start:

                charge_current = min_current

                charging_started = True

                voltage_below_stop = False # Reset the flag

                manual_start = False # Reset manual start flag

                print("Starting charging at minimum rate")

            # Control charge current based on voltage

            if charging_started:

                if voltage > setpoint_voltage:

                    charge_current = min(max_current, charge_current + 1)

                    print("Increasing charge rate by 1 Amps. New charge rate:", charge_current)

                elif voltage < setpoint_voltage:

                    if charge_current > min_current:

                        charge_current = max(min_current, charge_current - 1) # Enforce min_current

                        print("Decreasing charge rate by 1 Amps. New charge rate:", charge_current)

                    elif charge_current == min_current:

                        print("Charge rate is already at minimum.")

            print("Charge current:", charge_current)

            # Stop charging if voltage falls below stop_voltage

            if charging_started and voltage <= stop_voltage:

                charge_current = 0

                voltage_below_stop = True

                charging_started = False # Ensure charging is stopped

                print("Stopping charging due to voltage below stop_voltage")

            # Restart charging if voltage goes back above start_voltage after previously stopping

            if voltage >= start_voltage and voltage_below_stop:

                voltage_below_stop = False # Reset the flag

                print("Voltage back above start_voltage. Waiting for start_voltage to restart charging.")

            # Make/update claim on OpenEVSE with adjusted charge current

            payload = {

                "state": "active" if charge_current > 0 else "disabled",

                "charge_current": charge_current,

                "max_current": max_current,

                "auto_release": True

            }

            retries = 0

            while retries < max_retries:

                try:

                    response = requests.post(f"{openevse_api_url}/override", json=payload)

                    print("Response from OpenEVSE API:", response.text)

                    break

                except requests.RequestException as e:

                    print("Request failed:", e)

                    retries += 1

                    print("Retrying OpenEVSE command...")

                    time.sleep(5) # Wait before retrying

            if retries == max_retries:

                print("Max retries reached. Could not send command to OpenEVSE API.")

        time.sleep(30) # Adjust the polling interval as needed

# Start controlling charging

try:

    control_charging()

except Exception as e:

    print("An unexpected error occurred:", e)

    traceback.print_exc()


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


I have now added a simple GUI to the script and added some more safety features :)



py

I wish I could juts edit my last post, I found a bug in the logic that allowed for premature restart after low voltage events.  this has been fixed and the GUI improved :)

py

Aloha from Kekeha!
This is very similar to what I am trying to implement.


How are you reading the battery bank voltage?


Are you monitoring the house load and the inverter capacity as part of the EV charge current/load?
Any time of day limitations (don't start charging until batteries are a certain % of max voltage & its after 8am??)


So glad to have found your efforts. Thanks for posting! - Randy / boulderwise@proton.me



I have it setup to run fully off of battery voltage. In my case the time component is not critical, once the battery hits a voltage that equals 95% I want the evse on, then the logic tries to modulate the current to reach whatever equilibrium charge you set. In my case I know the voltage when I have 80% battery and set it there. Once the solar starts falling for the day and the battery drops to the 70% voltage it stops charging until it goes back up to 95%. It’s working great this way and pretty simple. The GUI has all the setpoint in it and they are easy to change. I use a Shelly Uni to measure the voltage. Cheap and simple. https://www.shelly.com/en-us/products/shop/shelly-uni-us

My home battery off-grid system is 48VDC. So my battery range is 47 to 57.
Is yours 24VDC, or do you use a voltage divider to measure your batteries (and power the Shelly UNI?)


Thanks, Randy

I actually have this script running on 3 separate systems that are not yet tied together, long story LOL.  2 of them are 48V and 1 is 24.  The 48V systems I use a voltage divider for the ADC (voltage) measurement, and a 48VDC to 12V DC converter to power the UNI.  You could also use something simple like a wall wort power supply to feed the UNI power, I didn't because I like to see teh DC voltage even if the inverter is faulted.  

I used this voltage divider.  It gives 1/5th the supply voltage.  amazon supplied voltage divider


Wow! I just got an Openevse kit and got it running. I largely chose it because I'm interested in (need) this off-grid self regulating concept. (off-grid for 50 years)

However I'm not much with the "computer" stuff so this looks pretty daunting. But it's also new territory and "maybe" I can muddle my way through. Might you be setting any of these up for sale by any chance?

Gary

James,

You may be done looking at this but if not I'll ask a few questions. (I have pretty much zero knowledge of any of this.) What you are doing sounds brilliant and just what I need/want.

What is "talking" to what? Your script is aimed at the Shelly or the EVSE? Maybe that will all become apparent as I dig in deeper....?


And the divider you linked is for 25 V so that must not be what you used on your 48V system...?

Thanks!!

Aloha Gary :)  Setting up python and running the script is very simple, you just need a device that can stay on and connected to the same network as the OPEN EVSE and Shelly uni (has to be the V1 version).  The more interesting part can be dialing in the voltages because there is absolutely going to be a variance between the inverter DC V, Uni "ADC" and actual DC voltage of the battery.  For whatever reason one of my  UNI is always 3.5V low, another is spot on...  The script is setup so you can make adjustments from a user interface and immediately apply them to the loop :)  


Installing python on a windows PC is as easy as any other program...   https://www.digitalocean.com/community/tutorials/install-python-windows-10


The script I supplied will then become executable.  Open it like any program


Input your  Open EVSE ID and Shelly uni IP address in the UI (Make them static for reliability, very straight forward in the shelly UI)


Put your voltage setpoints in the UI, Press "Update Settings"  then "start auto"  and thats it :)

I just realized I never published the newest version of this....   This iteration is much more user friendly :)  


You can see in these images the rate control happening on the float current, its adjusting to the voltage rise and fall of the battery.  


The other image is the GUI of the script.  This is where you can make adjustments easily to the needed variables.  The red boxes are site specific and need to be set based on you equipment. The voltage settings all need to be tailored to your specific needs also.  Once you have it all dialed in you can edit the script in notepad to change your values to the defaults.  Hopefully that makes the process less daunting :)


image

image

py

I saw this thread and exactly what I needed. Thanks for the post!


Gary, yes if you don't have any experience in computers it will be slightly challenging. Otherwise it's not so bad. I already have a raspberry pi (mini computer) that runs linux, which the python script above will run easily on it. Everything on it is pretty straightforward you just change the IP addresses of the devices and it should work (minus if you run a 48V system so have to buy that additional voltage divider and change some values in the script). You technically can even run the script on your computer, but that means leaving your computer running 24/7.


There is a delay in posting this message (due to moderators reviewing it) that makes it hard to have a quick discussion like other forums.

James and KL,

Thanks so much for keeping this topic going! I will certainly have some challenges with this as computer "stuff" is far from easy for me. But this is really what makes sense for our off-grid set-ups. So is it sort of like this?

 The computer (pi maybe) is where the script is stored and runs from. The Shelly sends the voltage readings to the computer and the computer sends directions to the EVSE? And all via WiFi...? 


All the voltage tweaking and adjusting is right up my alley......


I am going to be chipping away at this slowly so hopefully we can keep the discussion going....

Thanks!!!

Gary   Off-grid in Vermont

Aloha Gary :) The 25V voltage divider works perfectly with 60V :) they market it that way for a 5v target output, yours will be higher. The way the script works is this.. you run the script on a 24/7 on and connected device (pi, pc, Mac or whatever) supply the script the IP address of both the open evse and the Shelly device and setpoint voltages. The script will request the voltage from the Shelly device and then tell the open evse to start, stop or increase, decrease charge rate. It functions like this.. it asks for the voltage at the interval you set, then when the start voltage is exceeded (assuming you have the auto start enabled) the charging begins. After it’s begun the script will compare the voltage against the setpoint. If the setpoint is lower than the voltage it will increase the charge rate, if the setpoint is higher then it will decrease the charge rate. This limits the micro cycling on the batteries because the script is aiming to maintain a set voltage and limit battery current. Once the voltage falls below the stop setpoint it will stop charging until the start voltage is reached. Before I was using this script I was using a voltage based control and I would get hundreds of cycles applied to my battery every day.. with the script I accumulate a cycle a week and the power supplied to the evse is 30% more each day. It’s much better to modulate the charge rate than do stop and start

James,

So incredibly helpful!! This is exactly what makes sense. Really the same as controllers do for float. I think I will just get a pi as it seems they are fairly cheap and probably don't use a lot of power. And it will live in my shop where all this will get set up. Certainly will have learning curves over that! If I start with my MacBook is it easy to then set up a pi for the long term?


Still working out kinks on the station wifi but have a Shelly and divider ordered......

I sure hope you stick with this forum!!!!

Thanks so much!!!

Gary

Login or Signup to post a comment