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
30 changes: 24 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
FROM python:3 as builder
FROM python:3.13 AS builder

RUN python3 -m venv /opt/virtualenv \
&& apt-get update \
&& apt-get install build-essential
RUN python3 -m venv /opt/virtualenv && \
apt update && \
apt install -y build-essential

COPY requirements.txt ./
RUN /opt/virtualenv/bin/pip3 install --no-cache-dir -r requirements.txt

FROM python:3-slim
FROM python:3.13-slim

RUN useradd -r -m sungather
RUN apt update && apt upgrade -y && \
apt install -y procps sudo && \
apt clean autoclean && \
apt autoremove -y && \
rm -rf /tmp/* && \
rm -rf /usr/share/doc/* && \
rm -rf /usr/share/info/* && \
rm -rf /var/lib/{apt,cache,dpkg,log}/ && \
rm -rf /var/tmp/*

RUN groupadd -g 1000 sungather && \
useradd -u 1000 -g sungather -d /opt/sungather -s /bin/false sungather

RUN echo "sungather ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers && \
chmod 0440 /etc/sudoers && \
chmod g+w /etc/passwd

COPY --from=builder /opt/virtualenv /opt/virtualenv

WORKDIR /opt/sungather

COPY SunGather/ .

COPY patch/SungrowClient.py /opt/virtualenv/lib/python3.13/site-packages/SungrowClient/
RUN rm -rf /opt/virtualenv/lib/python3.13/site-packages/SungrowClient/__pycache__

VOLUME /logs
VOLUME /config
COPY SunGather/config-example.yaml /config/config.yaml
Expand Down
3 changes: 2 additions & 1 deletion SunGather/exports/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,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.warning(f'MQTT: {self.mqtt_queue.__len__()} messages queued.')
logging.warning(f'MQTT: Server Error: {err}')
return False
# qos=0 is set, so no acknowledgment is sent, rending this check useless
#elif self.mqtt_queue.__len__() > 10:
Expand Down
31 changes: 25 additions & 6 deletions SunGather/exports/pvoutput.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ def configure(self, config, inverter):
self.batch_data = []
self.batch_count = 0
self.last_run = 0
self.last_publish = 0

for parameter in config.get('parameters'):
if not inverter.validateRegister(parameter['register']):
Expand Down Expand Up @@ -110,6 +109,7 @@ def configure(self, config, inverter):
pass

logging.info(f"PVOutput: Configured export to {invertername} every {self.status_interval} minutes")
self.next_publish = datetime.datetime.now()
return True

def collect_data(self, inverter):
Expand Down Expand Up @@ -152,7 +152,7 @@ def collect_data(self, inverter):
def publish(self, inverter):
if self.collect_data(inverter):
# Process data points every status_interval
if((time.time() - self.last_publish) >= (self.status_interval * 60)):
if self.next_publish <= datetime.datetime.now():
any_data = False
if inverter.validateLatestScrape('timestamp'):
now = datetime.datetime.strptime(inverter.getRegisterValue('timestamp'), "%Y-%m-%d %H:%M:%S")
Expand Down Expand Up @@ -213,14 +213,33 @@ def publish(self, inverter):
logging.error("PVOutput: Request; " + self.url_addbatchstatus + ", " + str(self.headers) + " : " + str(payload))
else:
self.batch_data = []
self.last_publish = time.time()
self.next_publish = self.get_next_target_time(self.status_interval)
logging.info("PVOutput: Data uploaded")
except Exception as err:
logging.error(f"PVOutput: Failed to Upload")
logging.debug(f"{err}")
else:
logging.info("PVOutput: Data added to next batch upload")
else:
logging.info(f"PVOutput: Data logged, next upload in {int(((self.status_interval) * 60) - (time.time() - self.last_publish))} secs")

self.last_run = time.time()
next_upload_delta = self.next_publish - datetime.datetime.now()
logging.info("PVOutput: Data logged, next upload in %s secs", int(next_upload_delta.total_seconds()))

self.last_run = time.time()

def get_next_target_time(self, interval, delay=0):
"""Calculate the next time that we should send an update to pvoutput.

:param interval: (int) The time, in minutes, between updates. Must match
the setting on pvoutput for the system to which you're posting data.
:param delay: (int) The desired post-target delay, in seconds (for avoiding
updates at the same time as other systems that report data).

:return: A datetime.
"""
now = datetime.datetime.now()
wait_minutes = interval - (now.minute % interval) - 1
wait_seconds = 60 - now.second
target_delta = datetime.timedelta(minutes=wait_minutes, seconds=wait_seconds)
target_time = now + target_delta
target_time += datetime.timedelta(seconds=delay)
return target_time
2 changes: 1 addition & 1 deletion SunGather/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.5.2'
__version__ = '0.5.3-pbarbosa'
Loading