Skip to content

Commit 0e86918

Browse files
authored
Update wallbox_monitor.py
- limited log size to 10 mb - dynamically determines the script directory using os.path.abspath(__file__), ensures wallbox_monitor.credo and log files are always correctly found - all major actions (state changes, API requests, errors) are now logged - ensured, that the charging power notification is just sent once - better error handling, if the credo file could not be found or opened - if wallbox_state.txt does not exists, it will be created now
1 parent f0ca68f commit 0e86918

1 file changed

Lines changed: 45 additions & 12 deletions

File tree

wallbox_monitor.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#!/usr/bin/env python3
22

3+
# v1.0.3
4+
# shellrecharge-wallbox-monitor - by bjoerrrn
5+
# github: https://github.com/bjoerrrn/shellrecharge-wallbox-monitor
6+
# This script is licensed under GNU GPL version 3.0 or above
7+
8+
import os
39
import logging
410
import time
511
import re
@@ -10,20 +16,33 @@
1016
from selenium.webdriver.common.by import By
1117
from selenium.webdriver.support.ui import WebDriverWait
1218
from selenium.webdriver.support import expected_conditions as EC
19+
from logging.handlers import RotatingFileHandler
20+
21+
# Get script directory
22+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
1323

14-
LOG_FILE = "/home/pi/wallbox-monitor/wallbox_monitor.log"
15-
logging.basicConfig(filename=LOG_FILE, level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
24+
# Logging configuration with rotation
25+
LOG_FILE = os.path.join(SCRIPT_DIR, "wallbox_monitor.log")
26+
log_handler = RotatingFileHandler(LOG_FILE, maxBytes=10*1024*1024, backupCount=0)
27+
log_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
28+
logging.basicConfig(level=logging.INFO, handlers=[log_handler])
1629

17-
# Load configuration from credentials file
18-
CONFIG_FILE = "/home/pi/wallbox-monitor/wallbox_monitor.credo"
30+
# Load configuration file
31+
CONFIG_FILE = os.path.join(SCRIPT_DIR, "wallbox_monitor.credo")
1932
config = configparser.ConfigParser()
20-
config.read(CONFIG_FILE)
33+
34+
if not os.path.exists(CONFIG_FILE):
35+
logging.error("Configuration file missing. Ensure 'wallbox_monitor.credo' exists.")
36+
print("Error: Missing 'wallbox_monitor.credo'.")
37+
raise SystemExit("Error: Missing 'wallbox_monitor.credo'.")
2138

2239
try:
40+
config.read(CONFIG_FILE)
2341
WALLBOX_URL = config.get("CREDENTIALS", "WALLBOX_URL")
2442
DISCORD_WEBHOOK_URL = config.get("CREDENTIALS", "DISCORD_WEBHOOK_URL")
25-
except (configparser.NoSectionError, configparser.NoOptionError, FileNotFoundError) as e:
43+
except (configparser.NoSectionError, configparser.NoOptionError) as e:
2644
logging.error(f"Configuration error: {e}")
45+
print(f"Error loading credentials: {e}")
2746
raise SystemExit("Error loading credentials. Check 'wallbox_monitor.credo'.")
2847

2948
STATE_FILE = "/tmp/wallbox_state.txt"
@@ -79,6 +98,7 @@ def fetch_charging_status(driver):
7998

8099
except Exception as e:
81100
logging.error(f"Error fetching charging status: {e}")
101+
print(f"Error fetching charging status: {e}")
82102
return None, None
83103

84104

@@ -99,8 +119,10 @@ def send_discord_notification(message):
99119
try:
100120
requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=5)
101121
logging.info(f"Sent Discord notification: {message}")
122+
print(f"Sent Discord notification: {message}")
102123
except requests.RequestException as e:
103124
logging.error(f"Error sending Discord notification: {e}")
125+
print(f"Error sending Discord notification: {e}")
104126

105127
def get_last_state():
106128
"""Reads the last state and charging start time from the state file."""
@@ -113,10 +135,14 @@ def get_last_state():
113135
timestamp = float(parts[1]) if parts[1] != "None" else 0.0
114136
power = float(parts[2]) if parts[2] != "None" else 0.0
115137
return "charging", timestamp, power
116-
except ValueError:
138+
except ValueError as e:
139+
logging.error(f"Value Error: {e}")
140+
print(f"Value Error: {e}")
117141
return "idle", None, None # Reset to idle if parsing fails
118142
return data, None, None # "idle"
119-
except FileNotFoundError:
143+
except FileNotFoundError as e:
144+
with open(STATE_FILE, "w") as f:
145+
f.write("idle")
120146
return "idle", None, None
121147

122148
def save_last_state(state, charging_power=0.0):
@@ -136,6 +162,7 @@ def main():
136162
charging_rate, consumed_energy_wh = fetch_charging_status(driver)
137163

138164
print(f"🔍 Charging Rate: {charging_rate}, Consumed Energy: {consumed_energy_wh}")
165+
logging.info(f"🔍 Charging Rate: {charging_rate}, Consumed Energy: {consumed_energy_wh}")
139166

140167
if charging_rate is not None:
141168
new_state = "charging" if charging_rate >= 1.0 else "idle"
@@ -144,36 +171,42 @@ def main():
144171
timestamp = german_timestamp()
145172

146173
print(f"🔄 Last State: {last_state}, New State: {new_state}")
174+
logging.info(f"🔄 Last State: {last_state}, New State: {new_state}")
147175

148176
if last_state != new_state: # Only trigger on state change
149177
if new_state == "charging":
150178
message = f"⚡ {timestamp}: charging started."
151179
print(f"📢 Sending Discord Notification: {message}")
180+
logging.info(f"📢 Sending Discord Notification: {message}")
152181
send_discord_notification(message)
153182
save_last_state(new_state, charging_rate) # Store start time & power
154183
else:
155184
message = f"🔋 {timestamp}: charging stopped."
156185
print(f"📢 Sending Discord Notification: {message}")
186+
logging.info(f"📢 Sending Discord Notification: {message}")
157187
send_discord_notification(message)
158188
save_last_state(new_state) # Reset state
159189

160190
# If charging, check if 5 minutes have passed
161191
elif new_state == "charging" and start_time is not None:
162192
elapsed_time = time.time() - start_time
163193
print(f"⏳ Elapsed Charging Time: {elapsed_time:.2f} seconds")
194+
logging.info(f"⏳ Elapsed Charging Time: {elapsed_time:.2f} seconds")
164195

165-
if elapsed_time >= 300: # 300 seconds = 5 minutes
196+
if elapsed_time >= 300 and elapsed_time < 359: # 300 seconds = 5 minutes
166197
latest_charging_rate, _ = fetch_charging_status(driver) # Fetch latest power
167-
message = f" charging power: {latest_charging_rate:.2f} kW"
198+
message = f" charging power: {latest_charging_rate:.2f} kW"
168199
print(f"📢 Sending Discord Notification: {message}")
200+
logging.info(f"📢 Sending Discord Notification: {message}")
169201
send_discord_notification(message)
170-
save_last_state("charging") # Prevent duplicate notifications
202+
save_last_state("charging")
171203

172204
# If charging stopped, send a separate consumption message
173205
if last_state == "charging" and new_state == "idle" and consumed_energy_wh is not None:
174206
formatted_energy = format_energy(consumed_energy_wh)
175-
message = f" consumed energy: {formatted_energy}"
207+
message = f"🔍 consumed energy: {formatted_energy}"
176208
print(f"📢 Sending Discord Notification: {message}")
209+
logging.info(f"📢 Sending Discord Notification: {message}")
177210
send_discord_notification(message)
178211

179212
finally:

0 commit comments

Comments
 (0)