Documentation Index
Fetch the complete documentation index at: https://docs.directenergypartners.com/llms.txt
Use this file to discover all available pages before exploring further.
The main entry point for your custom application is the app/main.py file inside the dep-ppl-app repository. This
script handles the NATS connection to the PPL controller, sets up logging, and runs a continuous control loop where you
implement your custom logic.
You should edit this file directly to build your application. As your application grows, you can create additional modules
and a full folder structure inside the app folder to organize your code.
The Main Script
Below is the default main.py script included in the repository:
"""
Main entry point for the app.
"""
import logging
import os
import sys
import time
from dotenv import load_dotenv
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from pplapp import Pplapp
# -- Configuration ------------------------------------------------------------
STARTUP_DELAY_S = 5
CONTROL_LOOP_INTERVAL_S = 5
# -- Logging ------------------------------------------------------------------
log = logging.getLogger("app")
log.setLevel(logging.INFO)
formatter = logging.Formatter(
fmt="[%(asctime)s] %(levelname)s %(name)s %(message)s",
datefmt="%d.%m.%Y %H:%M:%S",
)
_project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
fileHandler = logging.FileHandler(os.path.join(_project_root, "app.log"))
fileHandler.setFormatter(formatter)
log.addHandler(fileHandler)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(formatter)
log.addHandler(consoleHandler)
# -- Main Application Logic ---------------------------------------------------
def ems(app):
# TODO: Implement energy management system logic
pass
def main() -> None:
load_dotenv()
ipAddress = os.getenv("IP_ADDRESS")
username = os.getenv("NATS_USERNAME")
password = os.getenv("NATS_PASSWORD")
if not ipAddress or not username or not password:
log.error("IP_ADDRESS, NATS_USERNAME, and NATS_PASSWORD must be set in .env")
sys.exit(1)
log.info("Connecting to PPL controller at %s", ipAddress)
app = Pplapp(ipAddress, username, password)
time.sleep(STARTUP_DELAY_S)
try:
while True:
try:
ems(app)
except Exception as e:
log.exception("Error in control loop: %s", e)
time.sleep(CONTROL_LOOP_INTERVAL_S)
except KeyboardInterrupt:
log.info("Shutdown requested")
app.stop()
log.info("Clean shutdown complete")
if __name__ == "__main__":
main()
How It Works
The script does the following:
- Loads environment variables from the
.env file (IP_ADDRESS, NATS_USERNAME, NATS_PASSWORD).
- Sets up logging to both the console and a file (
app.log in the project root).
- Connects to the controller using the
pplapp module.
- Runs a continuous control loop that calls the
ems() function at a configurable interval.
- Handles errors gracefully — exceptions in the loop are logged without crashing the application, and a keyboard interrupt triggers a clean shutdown.
The ems() function is where you implement your custom logic. The app parameter gives you access to all pplapp
module functions for reading data from and sending commands to the controller.
Extending Your Application
The app folder is your workspace. As your application grows beyond a single file, you can create a full folder structure
inside it. For example:
app/
├── __main__.py # Allows running the app with python -m app
├── main.py # Main entry point – edit this to implement your application
├── helpers/
│ ├── __init__.py
│ └── calculations.py
└── strategies/
├── __init__.py
└── peak_shaving.py
Import your modules in main.py and call them from the ems() function. This keeps your code modular and maintainable.