From 031b03c85012ab419170ddbf2b7be4331e8d475a Mon Sep 17 00:00:00 2001
From: britkat1980 <69121158+britkat1980@users.noreply.github.com>
Date: Tue, 1 Oct 2024 09:52:29 +0100
Subject: [PATCH 1/7] Update README.md
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 7364f77..a8fb516 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ GivTCP can auto-discover devices on the network for a (near) zero config setup
Typically run through the Home Assistant Addon, it is also possible to run as a standalone docker container.
+
+
## Quick Set-up
### Install GivTCP
From 6abfa4397c37d95f98c9ac0e1e6d5e384eb70de4 Mon Sep 17 00:00:00 2001
From: britkat1980 <69121158+britkat1980@users.noreply.github.com>
Date: Tue, 1 Oct 2024 09:54:40 +0100
Subject: [PATCH 2/7] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index a8fb516..e2da7e1 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ GivTCP can auto-discover devices on the network for a (near) zero config setup
Typically run through the Home Assistant Addon, it is also possible to run as a standalone docker container.
-
+
## Quick Set-up
From ac2bfe880c3df1a3315f6c420386064444056078 Mon Sep 17 00:00:00 2001
From: DanielGallo
Date: Tue, 1 Oct 2024 22:30:31 +0100
Subject: [PATCH 3/7] Fix GivTCP using wrong reference to WebDashboard
---
WebDashboard | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/WebDashboard b/WebDashboard
index 4dd6de5..510e5db 160000
--- a/WebDashboard
+++ b/WebDashboard
@@ -1 +1 @@
-Subproject commit 4dd6de564b77b0e29430446387185f0b548961d9
+Subproject commit 510e5dbf63fe80e721e11952cdc7e70f40afc832
From 5f48d03ac4b4482c4c8f12e9d9cad2ba051af76f Mon Sep 17 00:00:00 2001
From: DanielGallo
Date: Tue, 1 Oct 2024 22:56:12 +0100
Subject: [PATCH 4/7] Update WebDashboard
---
WebDashboard | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/WebDashboard b/WebDashboard
index 510e5db..9e39d08 160000
--- a/WebDashboard
+++ b/WebDashboard
@@ -1 +1 @@
-Subproject commit 510e5dbf63fe80e721e11952cdc7e70f40afc832
+Subproject commit 9e39d08a4124205848a6c57913b3e85a586d0dc9
From 88278304e06f2dac8ca731dad2619bfd7a733c34 Mon Sep 17 00:00:00 2001
From: DanielGallo
Date: Tue, 1 Oct 2024 23:54:38 +0100
Subject: [PATCH 5/7] Replace npm module "serve" with "http-server"
---
Dockerfile | 4 ++--
startup.py | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index fca5042..c78aa48 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,7 +12,7 @@ RUN apk add redis
RUN apk add nginx
RUN mkdir -p /run/nginx
-RUN npm install -g serve
+RUN npm install -g http-server
# set the working directory in the container
WORKDIR /app
@@ -43,6 +43,6 @@ COPY redis.conf redis.conf
COPY settings.json ./settings.json
COPY ingress/ ./ingress
-EXPOSE 1883 6379 8099
+EXPOSE 1883 3000 6379 8099
CMD ["python3", "/app/startup.py"]
diff --git a/startup.py b/startup.py
index d55c888..5651a4f 100644
--- a/startup.py
+++ b/startup.py
@@ -625,7 +625,7 @@ def findinv(networks):
outp.write("}")
WDPORT=int(setts['Web_Dash_Port'])
logger.info ("Serving Web Dashboard from port "+str(WDPORT))
- command=shlex.split("/usr/bin/node /usr/local/bin/serve -p "+ str(WDPORT))
+ command=shlex.split("/usr/bin/node /usr/local/bin/http-server -p "+ str(WDPORT))
webDash=subprocess.Popen(command)
@@ -678,7 +678,7 @@ def findinv(networks):
os.chdir("/app/WebDashboard")
WDPORT = int(setts['Web_Dash_Port'])
logger.info("Serving Web Dashboard from port " + str(WDPORT))
- command = shlex.split("/usr/bin/node /usr/local/bin/serve -p " + str(WDPORT))
+ command = shlex.split("/usr/bin/node /usr/local/bin/http-server -p " + str(WDPORT))
webDash = subprocess.Popen(command)
if setts['MQTT_Address']=="127.0.0.1":
From 71189d124876b5f75e82b94f621508ebad25bb7a Mon Sep 17 00:00:00 2001
From: Will Holley
Date: Fri, 18 Oct 2024 22:23:13 +0100
Subject: [PATCH 6/7] Dockerfile: remove node runtime
Why:
The websites served under WebDashboard and
givtcp-vuejs are status - there's no need to have
nodejs at runtime. Removing nodejs / npm and the
build-time dependencies shaves around 500MB from
the docker image (as well as reducing the CVE
surface).
How:
* Adds a builder stage which compiles givtcp-vuejs.
The resultant static files are copied into the
final image.
* Removes npm and http-server from the runtime image.
* Adds exclusions to .dockerignore for some of the
Webdashboard files that have no runtime purpose.
* Updates startup.py to write out nginx configuration
that serves WebDashboard as a static site.
This is only really needed because the dashboard port
is configurable/toggleable - else we could just
define this in the standard ingress.conf.
---
.dockerignore | 8 ++++++++
Dockerfile | 24 ++++++++++++++++--------
startup.py | 47 ++++++++++++++++++++++++-----------------------
3 files changed, 48 insertions(+), 31 deletions(-)
diff --git a/.dockerignore b/.dockerignore
index b02b2dd..1fc80ed 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -5,3 +5,11 @@ GivTCP/startup.sh
*.pkl
.forceFullRefresh
test.txt
+.git
+.vscode
+Dockerfile
+WebDashboard/graphics
+
+# WebDashboard is a static site - node is not required
+# except as a helper to serve the site for development
+WebDashboard/package*
diff --git a/Dockerfile b/Dockerfile
index c78aa48..3757356 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,21 @@
+# givtcp-vuejs builder
+FROM node:21-alpine AS givtcp_vuejs_tmp
+
+# set the working directory in the container
+WORKDIR /app
+
+# Copy file dependencies in a single layer
+COPY givtcp-vuejs .
+
+RUN npm install && \
+ npm run build && \
+ mv dist/index.html dist/config.html
+
# set base image (host OS)
#FROM python:3.11-rc-alpine
FROM python:alpine3.19
RUN apk add mosquitto
-RUN apk add npm
RUN apk add git
RUN apk add tzdata
RUN apk add musl
@@ -12,7 +24,6 @@ RUN apk add redis
RUN apk add nginx
RUN mkdir -p /run/nginx
-RUN npm install -g http-server
# set the working directory in the container
WORKDIR /app
@@ -21,12 +32,6 @@ WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
-COPY givtcp-vuejs/package.json /app/ingress/package.json
-
-RUN cd /app/ingress && npm install
-COPY givtcp-vuejs ./ingress
-RUN cd /app/ingress && npm run build && mv dist/index.html dist/config.html && cp -a dist/. /app/ingress/
-
COPY ingress.conf /etc/nginx/http.d/
COPY ingress_no_ssl.conf /app/ingress_no_ssl.conf
RUN rm /etc/nginx/http.d/default.conf
@@ -43,6 +48,9 @@ COPY redis.conf redis.conf
COPY settings.json ./settings.json
COPY ingress/ ./ingress
+# Copy static site files
+COPY --from=givtcp_vuejs_tmp /app/dist /app/ingress/
+
EXPOSE 1883 3000 6379 8099
CMD ["python3", "/app/startup.py"]
diff --git a/startup.py b/startup.py
index 5651a4f..149728e 100644
--- a/startup.py
+++ b/startup.py
@@ -125,7 +125,7 @@ def createsettingsjson(inv):
outp.write(" first_run_evc= True\n")
outp.write(" self_run_timer="+str(setts["self_run_timer"])+"\n")
outp.write(" self_run_timer_full="+str(setts["self_run_timer_full"])+"\n")
- outp.write(" queue_retries="+str(setts["queue_retries"])+"\n")
+ outp.write(" queue_retries="+str(setts["queue_retries"])+"\n")
outp.write(" givtcp_instance="+str(inv)+"\n")
outp.write(" default_path=\""+str(PATH)+"\"\n")
outp.write(" dynamic_tariff="+str(setts["dynamic_tariff"]).capitalize()+"\n")
@@ -286,7 +286,7 @@ def findinv(networks):
hasMQTT=False
logger.info("No HA MQTT service has been found. Install and run the Mosquitto addon, or manually configure your own MQTT broker.")
- #Get Timezone
+ #Get Timezone
url="http://supervisor/info"
result = requests.get(url,
headers={'Content-Type':'application/json',
@@ -294,8 +294,8 @@ def findinv(networks):
info=result.json()
SuperTimezone=info['data']['timezone']
logger.debug("Supervisor Timezone: "+str(SuperTimezone))
-
- #Get addonslug/ingress url
+
+ #Get addonslug/ingress url
url="http://supervisor/addons/self/info"
result = requests.get(url,
headers={'Content-Type':'application/json',
@@ -303,7 +303,7 @@ def findinv(networks):
baseurl=result.json()['data']['ingress_url']
logger.debug("Ingress URL is: "+str(baseurl))
- #Get Host Details
+ #Get Host Details
url="http://supervisor/network/info"
result = requests.get(url,
headers={'Content-Type':'application/json',
@@ -352,8 +352,8 @@ def findinv(networks):
logger.info("Searching for Inverters")
finv=findinv(networks)
i=i+1
- if i==3:
- break
+ if i==3:
+ break
inverterStats=finv[0]
invList=finv[1]
evcList=finv[2]
@@ -436,7 +436,7 @@ def findinv(networks):
setts["invertorIP_"+str(num)]=inverterStats[inv]['IP_Address']
break
setts['Model_'+str(inv)]=inverterStats[inv]['Model'].name.capitalize()
-
+
if len(evcList)>0:
logger.debug("evcList: "+str(evcList))
@@ -540,7 +540,7 @@ def findinv(networks):
os.remove(firstrun)
createsettingsjson(inv)
-
+
######
# Always delete lockfiles and FCRunning etc... but only delete pkl if too old?
for file in os.listdir(setts["cache_location"]):
@@ -585,7 +585,7 @@ def findinv(networks):
logger.info ("Running Invertor "+str(inv)+" ("+str(setts["serial_number_"+str(inv)])+") read loop every "+str(setts['self_run_timer'])+"/"+str(setts['self_run_timer_full'])+"s")
selfRun[inv]=subprocess.Popen(["/usr/local/bin/python3",PATH+"/read.py", "start"])
-
+
GUPORT=6344+inv
logger.debug ("Starting Gunicorn on port "+str(GUPORT))
command=shlex.split("/usr/local/bin/gunicorn -w 3 -b :"+str(GUPORT)+" REST:giv_api")
@@ -623,10 +623,21 @@ def findinv(networks):
outp.write(" \"solarRate\": "+str(setts['day_rate'])+",\n")
outp.write(" \"exportRate\": "+str(setts['export_rate'])+"\n")
outp.write("}")
+
WDPORT=int(setts['Web_Dash_Port'])
- logger.info ("Serving Web Dashboard from port "+str(WDPORT))
- command=shlex.split("/usr/bin/node /usr/local/bin/http-server -p "+ str(WDPORT))
- webDash=subprocess.Popen(command)
+ logger.info (f"Serving Web Dashboard from port {WDPORT}")
+ with open("/etc/nginx/http.d/webdashboard.conf", 'w') as wd:
+ wd.write("server {\n")
+ wd.write(f"\tlisten {WDPORT};\n")
+ wd.write("\tlocation / {\n")
+ wd.write("\t\troot /app/WebDashboard;\n")
+ wd.write("\t\tindex index.html;\n\n")
+ wd.write("\t\ttry_files $uri $uri/ =404;\n")
+ wd.write("\t}\n")
+ wd.write("}\n")
+
+ # reload nginx to pick up the new conf
+ subprocess.Popen(["nginx","-s","reload", "-c", "/etc/nginx/nginx.conf"])
if setts['Smart_Target']==True:
@@ -670,16 +681,6 @@ def findinv(networks):
logger.info ("Starting Gunicorn on port "+str(GUPORT))
command=shlex.split("/usr/local/bin/gunicorn -w 3 -b :"+str(GUPORT)+" REST:giv_api")
gunicorn[inv]=subprocess.Popen(command)
-
- if setts['Web_Dash'] == True:
- if not webDash.poll() == None:
- webDash.kill()
- logger.error("Web Dashboard process died. Restarting...")
- os.chdir("/app/WebDashboard")
- WDPORT = int(setts['Web_Dash_Port'])
- logger.info("Serving Web Dashboard from port " + str(WDPORT))
- command = shlex.split("/usr/bin/node /usr/local/bin/http-server -p " + str(WDPORT))
- webDash = subprocess.Popen(command)
if setts['MQTT_Address']=="127.0.0.1":
if not mqttBroker.poll()==None:
From b7ff9c4721483203b9e904478bdcdbc1bd6443be Mon Sep 17 00:00:00 2001
From: britkat1980 <69121158+britkat1980@users.noreply.github.com>
Date: Sat, 19 Oct 2024 21:18:27 +0100
Subject: [PATCH 7/7] commit
---
WebDashboard | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/WebDashboard b/WebDashboard
index 9e39d08..6ec2a6f 160000
--- a/WebDashboard
+++ b/WebDashboard
@@ -1 +1 @@
-Subproject commit 9e39d08a4124205848a6c57913b3e85a586d0dc9
+Subproject commit 6ec2a6ff400159565e3f7667017282a404b826f1