The code below describes an application to manage the state of charge of a battery system. It continuously checks the
battery’s SOC and adjusts the power setpoint to charge or discharge the battery towards a target SOC, constrained by
predefined minimum and maximum SOC levels. The power setpoint is limited by the maximum import/export capabilities of
the converter and the charge/discharge limits of the battery. Commands are then sent to the converter to adjust its
power output accordingly. The script runs in an infinite loop with a specified delay between each iteration, and it
handles exceptions and graceful shutdown on user interruption.
target-soc.py
Copy
import timefrom pplapp import Pplappfrom dotenv import load_dotenvimport osload_dotenv()# Constants:startupDelay = 5executionDelay = 5POWER = 10000MINSOC = 20MAXSOC = 90TARGETSOC = 75batteryId = "battery1"converterId = "converter1"# Main function:def batteryTargetSOC(app): # Check if target SOC is within limits targetSoc = limit(TARGETSOC, MINSOC, MAXSOC) # Battery reported State of Charge soc = int(float(app.getMeasurements(batteryId, "measure.ports.port1.soc"))) if soc < targetSoc: powerSetpoint = -POWER # Charge the battery, need to set negative power setpoint to converter port elif soc > targetSoc: powerSetpoint = POWER # Discharge the battery, need to set positive power setpoint to converter port else: powerSetpoint = 0 # Check if power setpoint is within limits of the converter converterImportPowerMax = int(app.getMeasurements(converterId, "measure.ports.port2.power.import.max")) converterExportPowerMax = int(app.getMeasurements(converterId, "measure.ports.port2.power.export.max")) powerSetpoint = limit(powerSetpoint, converterExportPowerMax, converterImportPowerMax) # Check if power setpoint is within limits of the battery batteryChargePowerMax = int(app.getMeasurements(batteryId, "measure.ports.port1.power.charge.max")) batteryDischargePowerMax = int(app.getMeasurements(batteryId, "measure.ports.port1.power.discharge.max")) powerSetpoint = limit(powerSetpoint, -batteryChargePowerMax, batteryDischargePowerMax) setPower(app, powerSetpoint) print(f"Battery SOC: {soc}% - Target SOC: {targetSoc}%") print("Power Setpoint: " + str(powerSetpoint) + "W")# Helper functions:def limit(setpoint, minimum, maximum): return max(min(setpoint, maximum), minimum)def setPower(app, powerSetpoint): commands = { "control.ports.port2.method": "constant-power", "control.ports.port2.power": str(powerSetpoint) } app.setCommands(converterId, commands)def disableBatteryPort(app): commands = { "control.ports.port2.method": "disabled", "control.ports.port2.power": str(0) } app.setCommands(converterId, commands)def main(): try: ipAddress = "192.168.1.10" username = os.getenv("NATS_USERNAME") password = os.getenv("NATS_PASSWORD") if not username or not password: raise ValueError("NATS username or password not set in environment variables") app = Pplapp(ipAddress, username, password) time.sleep(startupDelay) while True: batteryTargetSOC(app) time.sleep(executionDelay) except Exception as e: print(f"Failed to initialize battery Target SOC: {e}") except KeyboardInterrupt: disableBatteryPort(app) time.sleep(executionDelay) app.connectToNats = Falseif __name__ == "__main__": main()