Replies: 1 comment 4 replies
-
One approach would be to create a small containerized python app that loads a configl.yaml that defines the schedule you want. It would then basically just wait for those time spots and run the command to switch the system mode. The pypowerwall service has a control mode that you can activate (see here). It requires:
That just allows you to change the mode and reserver values via URL calls: export MODE=self_consumption # or autonomous
export RESERVE=20
export PW_CONTROL_SECRET=YourSecretToken
# Set Mode
curl -X POST -d "value=$MODE&token=$PW_CONTROL_SECRET" http://localhost:8675/control/mode
# Set Reserve
curl -X POST -d "value=$RESERVE&token=$PW_CONTROL_SECRET" http://localhost:8675/control/reserve
# Read Settings
curl http://localhost:8675/control/mode As for the scheduler, I asked ChatGPT to create one and it came up with this idea: config.yaml # config.yaml
schedules:
- time: "14:30"
mode: "self power"
- time: "04:45"
mode: "timebased" server.py import yaml
import threading
import time as t
from datetime import datetime
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
import uvicorn
import requests # Import requests to make HTTP POST calls
# ----- Powerwall Control Settings -----
# Update these as needed.
PW_CONTROL_SECRET = "YourSecretToken"
MODE_URL = "http://localhost:8675/control/mode"
RESERVE_URL = "http://localhost:8675/control/reserve"
# ----- FastAPI App Initialization -----
app = FastAPI()
# Load the YAML configuration file.
try:
with open("config.yaml", "r") as file:
config = yaml.safe_load(file)
except Exception as e:
print(f"Error reading YAML configuration: {e}")
config = {}
# Read schedules from configuration.
schedules = config.get("schedules", [])
# Parse schedules into a list of dictionaries, including a parsed time object.
parsed_schedules = []
for schedule in schedules:
schedule_time_str = schedule.get("time", "00:00")
schedule_mode = schedule.get("mode", "self power")
try:
schedule_time_obj = datetime.strptime(schedule_time_str, "%H:%M").time()
except ValueError as e:
print(f"Error parsing time {schedule_time_str}: {e}. Using default 00:00")
schedule_time_obj = datetime.strptime("00:00", "%H:%M").time()
parsed_schedules.append({
"time_str": schedule_time_str,
"time_obj": schedule_time_obj,
"mode": schedule_mode
})
# ----- Powerwall Control Functions Using HTTP POST Calls -----
def set_selfpower():
"""Set the Powerwall to self power mode by sending POST requests.
This sets the mode to 'self_consumption'
"""
try:
print("Changing Powerwall mode to self_consumption...")
mode_response = requests.post(
MODE_URL,
data={"value": "autonomous", "token": PW_CONTROL_SECRET}
)
mode_response.raise_for_status()
print("Powerwall mode successfully set to self_consumption.")
except Exception as e:
print("Error setting self power mode:", e)
def set_timebased():
"""Set the Powerwall to timebased mode by sending a POST request."""
try:
print("Changing Powerwall mode to timebased...")
mode_response = requests.post(
MODE_URL,
data={"value": "timebased", "token": PW_CONTROL_SECRET}
)
mode_response.raise_for_status()
print("Powerwall mode successfully set to timebased.")
except Exception as e:
print("Error setting timebased mode:", e)
# ----- Background Thread: Monitor Time and Execute Scheduled Events -----
def time_monitor():
# Use a dictionary to track if an event has been triggered in its current minute window.
triggered_flags = {i: False for i in range(len(parsed_schedules))}
while True:
now = datetime.now().time()
for index, schedule in enumerate(parsed_schedules):
sched_time = schedule["time_obj"]
# If the current hour and minute match the scheduled time…
if now.hour == sched_time.hour and now.minute == sched_time.minute:
if not triggered_flags[index]:
print(f"Time condition met for schedule {index} ({schedule['time_str']} - {schedule['mode']}).")
if schedule["mode"].lower() == "self power":
set_selfpower()
elif schedule["mode"].lower() == "timebased":
set_timebased()
else:
print(f"Unknown mode in configuration for schedule index {index}.")
triggered_flags[index] = True
else:
# Reset the trigger flag once outside the scheduled minute.
triggered_flags[index] = False
t.sleep(1)
# Start the background thread (daemon) so it exits when the app shuts down.
thread = threading.Thread(target=time_monitor, daemon=True)
thread.start()
# ----- FastAPI Route: Display Configuration -----
@app.get("/", response_class=HTMLResponse)
def display_config():
table_rows = ""
for schedule in parsed_schedules:
table_rows += f"""
<tr>
<td>{schedule['time_str']}</td>
<td>{schedule['mode']}</td>
</tr>
"""
html_content = f"""
<html>
<head>
<title>Powerwall Schedule Configuration</title>
</head>
<body>
<h2>Current Schedule Configuration</h2>
<table border="1" cellpadding="5" cellspacing="0">
<tr>
<th>Time</th>
<th>Mode</th>
</tr>
{table_rows}
</table>
</body>
</html>
"""
return html_content
# ----- Run the FastAPI App -----
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000) |
Beta Was this translation helpful? Give feedback.
4 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Hi, all,
I am successfully running the Powerwall-Dashboard on Synology Docker without any problems.
I am wondering if there is a way to schedule a job to set the mode (self-power or time-based) within the current Powerwall-Dashboard setup.
At the moment, I create a virtual machine and use pyPowerwall to accomplish this task. Ideally, I hope to find a method to integrate this functionality directly into the existing Powerwall-Dashboard setup.
thanks.
Beta Was this translation helpful? Give feedback.
All reactions