Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
config.yaml
*.log.*

# Private notes directory
.private/

# Claude Code settings
.claude/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
5 changes: 4 additions & 1 deletion SunGather/exports/influxdb.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import influxdb_client
import logging
import traceback
from influxdb_client.client.write_api import SYNCHRONOUS

class export_influxdb(object):
Expand Down Expand Up @@ -67,7 +68,9 @@ def publish(self, inverter):
try:
self.write_api.write(self.influxdb_config['bucket'], self.client.org, sequence)
except Exception as err:
logging.error("InfluxDB: " + str(err))
logging.error(f"InfluxDB: Failed to write to bucket '{self.influxdb_config['bucket']}': {err}")
logging.debug(traceback.format_exc())
return False

logging.info("InfluxDB: Published")

Expand Down
10 changes: 6 additions & 4 deletions SunGather/exports/mqtt.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import json
import traceback
import paho.mqtt.client as mqtt

class export_mqtt(object):
Expand Down Expand Up @@ -61,20 +62,20 @@ def on_connect(self, client, userdata, flags, reason_code, properties):
if reason_code == 0:
logging.info(f"MQTT: Connected to {client._host}:{client._port}")
if reason_code > 0:
logging.warn(f"MQTT: FAILED to connect {client._host}:{client._port}")
logging.warning(f"MQTT: Failed to connect to {client._host}:{client._port} with code {reason_code}")

def on_disconnect(self, client, userdata, flags, reason_code, properties):
if reason_code == 0:
logging.info(f"MQTT: Server Disconnected")
if reason_code > 0:
logging.warn(f"MQTT: FAILED to disconnect {reason_code}")
logging.warning(f"MQTT: Disconnect failed with code {reason_code}")


def on_publish(self, client, userdata, mid, reason_codes, properties):
try:
self.mqtt_queue.remove(mid)
except Exception as err:
pass
logging.debug(f"MQTT: Message ID {mid} not found in queue: {err}")
logging.debug(f"MQTT: Message {mid} Published")

def cleanName(self, name):
Expand All @@ -85,7 +86,8 @@ def publish(self, inverter):
if not self.mqtt_client.is_connected():
logging.warning(f'MQTT: Server Disconnected; {self.mqtt_queue.__len__()} messages queued, will automatically attempt to reconnect')
except Exception as err:
logging.warning(f'MQTT: Server Error; Server not configured')
logging.error(f'MQTT: Error checking connection status: {err}')
logging.debug(traceback.format_exc())
return False
# qos=0 is set, so no acknowledgment is sent, rending this check useless
#elif self.mqtt_queue.__len__() > 10:
Expand Down
20 changes: 16 additions & 4 deletions SunGather/exports/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import json
import logging
import traceback
import urllib

class export_webserver(object):
Expand Down Expand Up @@ -108,10 +109,21 @@ def do_GET(self):
self.wfile.write(bytes("</body></html>", "utf-8"))

def do_POST(self):
length = int(self.headers['Content-Length'])
post_data = urllib.parse.parse_qs(self.rfile.read(length).decode('utf-8'))
logging.info(f"{post_data}")
self.wfile.write(post_data.encode("utf-8"))
try:
length = int(self.headers.get('Content-Length', 0))
if length > 0:
post_data = urllib.parse.parse_qs(self.rfile.read(length).decode('utf-8'))
logging.info(f"Webserver POST: {post_data}")
self.wfile.write(str(post_data).encode("utf-8"))
else:
self.send_response(400)
self.end_headers()
self.wfile.write(b"Bad Request: Missing Content-Length")
except Exception as e:
logging.error(f"Webserver: Error handling POST request: {e}")
logging.debug(traceback.format_exc())
self.send_response(500)
self.end_headers()

def log_message(self, format, *args):
pass
26 changes: 19 additions & 7 deletions SunGather/sungather.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import yaml
import time
import signal
import traceback

def main():
configfilename = 'config.yaml'
Expand Down Expand Up @@ -137,12 +138,19 @@ def main():
try:
if export.get('enabled', False):
export_load = importlib.import_module("exports." + export.get('name'))
logging.info(f"Loading Export: exports {export.get('name')}")
exports.append(getattr(export_load, "export_" + export.get('name'))())
retval = exports[-1].configure(export, inverter)
logging.info(f"Loading Export: {export.get('name')}")
export_instance = getattr(export_load, "export_" + export.get('name'))()

if export_instance.configure(export, inverter):
exports.append(export_instance)
logging.info(f"Successfully configured export: {export.get('name')}")
else:
logging.error(f"Export {export.get('name')} configuration failed - skipping")
except ModuleNotFoundError as err:
logging.error(f"Export module not found: {export.get('name')}.py - {err}")
except Exception as err:
logging.error(f"Failed loading export: {err}" +
f"\n\t\t\t Please make sure {export.get('name')}.py exists in the exports folder")
logging.error(f"Failed loading export {export.get('name')}: {err}")
logging.debug(traceback.format_exc())

scan_interval = config_inverter.get('scan_interval')

Expand All @@ -163,11 +171,15 @@ def main():

if(success):
for export in exports:
export.publish(inverter)
try:
export.publish(inverter)
except Exception as e:
logging.error(f"Export {export.__class__.__name__} failed: {e}")
logging.debug(traceback.format_exc())
if not inverter.inverter_config['connection'] == "http": inverter.close()
else:
inverter.disconnect()
logging.warning(f"Data collection failed, skipped exporting data. Retying in {scan_interval} secs")
logging.warning(f"Data collection failed, skipped exporting data. Retrying in {scan_interval} secs")

loop_end = time.perf_counter()
process_time = round(loop_end - loop_start, 2)
Expand Down