Upgrade to go1.16, use go:embed for bundling assets (#555)
44
.github/workflows/build.yml
vendored
|
|
@ -13,15 +13,14 @@ jobs:
|
|||
- name: Setup
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.14
|
||||
go-version: ^1.16
|
||||
id: go
|
||||
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
**/node_modules
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/package-lock.json') }}
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
||||
|
|
@ -34,7 +33,7 @@ jobs:
|
|||
run: make install
|
||||
|
||||
- name: Assets & UI
|
||||
run: make npm assets
|
||||
run: make assets
|
||||
|
||||
- name: Porcelain
|
||||
run: |
|
||||
|
|
@ -52,13 +51,40 @@ jobs:
|
|||
- name: Test
|
||||
run: make test
|
||||
|
||||
build-ui:
|
||||
name: Build UI
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
**/node_modules
|
||||
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-npm-
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install tools
|
||||
run: make install-ui
|
||||
|
||||
- name: Assets & UI
|
||||
run: make ui
|
||||
|
||||
- name: Porcelain
|
||||
run: |
|
||||
test -z "$(git status --porcelain)" || (git status; git diff; false)
|
||||
|
||||
dockerlatest:
|
||||
name: Publish :latest
|
||||
if: |
|
||||
startsWith(github.ref, 'refs/heads/master')
|
||||
&& ! contains(github.head_ref, 'refs/heads/chore/')
|
||||
needs: build
|
||||
needs:
|
||||
- build
|
||||
- build-ui
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
@ -83,7 +109,9 @@ jobs:
|
|||
dockerrelease:
|
||||
name: Publish :release
|
||||
if: "startsWith(github.ref, 'refs/tags')"
|
||||
needs: build
|
||||
needs:
|
||||
- build
|
||||
- build-ui
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
@ -109,7 +137,9 @@ jobs:
|
|||
release:
|
||||
name: Release
|
||||
if: "startsWith(github.ref, 'refs/tags')"
|
||||
needs: build
|
||||
needs:
|
||||
- build
|
||||
- build-ui
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
|
|||
1
.gitignore
vendored
|
|
@ -13,5 +13,4 @@ evcc_*
|
|||
flags/*
|
||||
buildflags/*
|
||||
linux-*.Dockerfile
|
||||
dist
|
||||
node_modules
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@ release:
|
|||
github:
|
||||
owner: andig
|
||||
name: evcc
|
||||
# before:
|
||||
# hooks:
|
||||
# - make npm assets
|
||||
extra_files:
|
||||
- glob: evcc_*.image.gz
|
||||
- glob: evcc_*.rootfs.gz
|
||||
|
|
|
|||
51
Dockerfile
|
|
@ -1,39 +1,50 @@
|
|||
#
|
||||
# STEP 1 build executable binary
|
||||
#
|
||||
# STEP 1 build ui
|
||||
FROM node:14-alpine as node
|
||||
|
||||
FROM golang:1.14-alpine as builder
|
||||
|
||||
# Install git + SSL ca certificates.
|
||||
# Git is required for fetching the dependencies.
|
||||
# Ca-certificates is required to call HTTPS endpoints.
|
||||
RUN apk update && apk add --no-cache git ca-certificates tzdata alpine-sdk npm && update-ca-certificates
|
||||
RUN apk update && apk add --no-cache make
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# cache modules
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
RUN go mod download
|
||||
|
||||
# install go and node tools
|
||||
# install node tools
|
||||
COPY Makefile .
|
||||
COPY package*.json ./
|
||||
RUN make install
|
||||
RUN make install-ui
|
||||
|
||||
# build ui
|
||||
COPY assets assets
|
||||
COPY vue.config.js vue.config.js
|
||||
RUN make clean npm
|
||||
RUN make clean ui
|
||||
|
||||
|
||||
# STEP 2 build executable binary
|
||||
FROM golang:1.16-alpine as builder
|
||||
|
||||
# Install git + SSL ca certificates.
|
||||
# Git is required for fetching the dependencies.
|
||||
# Ca-certificates is required to call HTTPS endpoints.
|
||||
RUN apk update && apk add --no-cache git ca-certificates tzdata alpine-sdk && update-ca-certificates
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# install go tools and cache modules
|
||||
COPY Makefile .
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
RUN make install
|
||||
RUN go mod download
|
||||
|
||||
# prepare
|
||||
COPY . .
|
||||
RUN make assets
|
||||
|
||||
# copy ui
|
||||
COPY --from=node /build/dist /build/dist
|
||||
|
||||
# build
|
||||
RUN make build
|
||||
|
||||
#
|
||||
# STEP 2 build a small image including module support
|
||||
#
|
||||
|
||||
# STEP 3 build a small image including module support
|
||||
FROM alpine:3.12
|
||||
|
||||
WORKDIR /evcc
|
||||
|
|
|
|||
36
Makefile
|
|
@ -1,6 +1,6 @@
|
|||
.PHONY: default clean install lint test assets build binaries test-release release
|
||||
.PHONY: publish-testing publish-latest publish-images
|
||||
.PHONY: image image-rootfs image-update
|
||||
.PHONY: default all clean install install-ui ui assets lint test build test-release release
|
||||
.PHONY: docker publish-testing publish-latest publish-images
|
||||
.PHONY: prepare-image image-rootfs image-update
|
||||
|
||||
# build vars
|
||||
TAG_NAME := $(shell test -d .git && git describe --abbrev=0 --tags)
|
||||
|
|
@ -13,7 +13,7 @@ BUILD_ARGS := -ldflags='$(LD_FLAGS)'
|
|||
|
||||
# docker
|
||||
DOCKER_IMAGE := andig/evcc
|
||||
ALPINE_VERSION := 3.12
|
||||
ALPINE_VERSION := 3.13
|
||||
TARGETS := arm.v6,arm.v8,amd64
|
||||
|
||||
# image
|
||||
|
|
@ -21,16 +21,25 @@ IMAGE_FILE := evcc_$(TAG_NAME).image
|
|||
IMAGE_ROOTFS := evcc_$(TAG_NAME).rootfs
|
||||
IMAGE_OPTIONS := -hostname evcc -http_port 8080 github.com/gokrazy/serial-busybox github.com/gokrazy/breakglass github.com/andig/evcc
|
||||
|
||||
default: clean install npm assets lint test build
|
||||
default: build
|
||||
|
||||
all: clean install install-ui ui assets lint test build
|
||||
|
||||
clean:
|
||||
rm -rf dist/
|
||||
|
||||
install:
|
||||
go install github.com/mjibson/esc
|
||||
go install github.com/golang/mock/mockgen
|
||||
|
||||
install-ui:
|
||||
npm ci
|
||||
|
||||
ui:
|
||||
npm run build
|
||||
|
||||
assets:
|
||||
go generate ./...
|
||||
|
||||
lint:
|
||||
golangci-lint run
|
||||
npm run lint
|
||||
|
|
@ -39,17 +48,6 @@ test:
|
|||
@echo "Running testsuite"
|
||||
go test ./...
|
||||
|
||||
npm:
|
||||
npm run build
|
||||
|
||||
ui:
|
||||
npm run build
|
||||
go generate main.go
|
||||
|
||||
assets:
|
||||
@echo "Generating embedded assets"
|
||||
go generate ./...
|
||||
|
||||
build:
|
||||
@echo Version: $(VERSION) $(BUILD_DATE)
|
||||
go build -v $(BUILD_TAGS) $(BUILD_ARGS)
|
||||
|
|
@ -60,6 +58,10 @@ release-test:
|
|||
release:
|
||||
goreleaser --rm-dist
|
||||
|
||||
docker:
|
||||
@echo Version: $(VERSION) $(BUILD_DATE)
|
||||
docker build --tag $(DOCKER_IMAGE):testing .
|
||||
|
||||
publish-testing:
|
||||
@echo Version: $(VERSION) $(BUILD_DATE)
|
||||
seihon publish --dry-run=false --template docker/tmpl.Dockerfile --base-runtime-image alpine:$(ALPINE_VERSION) \
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ When using Docker with a device that requires multicast UDP like SMA, make sure
|
|||
docker run --network host andig/evcc ...
|
||||
```
|
||||
|
||||
To build EVCC from source, [Go](2) 1.13 and [Node](3) 14 are required:
|
||||
To build EVCC from source, [Go](2) 1.16 and [Node](3) 14 are required:
|
||||
|
||||
make
|
||||
|
||||
|
|
|
|||
118
cmd/demo.go
|
|
@ -1,127 +1,15 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
_ "embed" // for yaml
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const demoYaml = `
|
||||
log: info
|
||||
|
||||
javascript:
|
||||
- vm: shared
|
||||
script: |
|
||||
state = {
|
||||
residualpower: 200,
|
||||
pvpower: -3000,
|
||||
batterypower: 200,
|
||||
gridpower: -2000,
|
||||
chargepower: 0,
|
||||
maxcurrent: 0,
|
||||
battery: 63, // car
|
||||
};
|
||||
function get() {
|
||||
console.log("state:", JSON.stringify(state));
|
||||
}
|
||||
function set() {
|
||||
console.log(param+":", val);
|
||||
console.log("state:", JSON.stringify(state));
|
||||
}
|
||||
|
||||
meters:
|
||||
- name: grid
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.gridpower = state.pvpower + state.chargepower + state.residualpower + state.batterypower;
|
||||
|
||||
- name: pv
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.pvpower += 100*Math.random();
|
||||
|
||||
- name: battery
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.batterypower;
|
||||
soc:
|
||||
type: js
|
||||
vm: shared
|
||||
script: "30"
|
||||
- name: charge
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.chargepower;
|
||||
soc:
|
||||
type: js
|
||||
vm: shared
|
||||
script: "30"
|
||||
|
||||
chargers:
|
||||
- name: demo
|
||||
type: default
|
||||
enable:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
set();
|
||||
state.enabled = val;
|
||||
if (state.enabled) state.chargepower = state.maxcurrent * 230; else state.chargepower = 0;
|
||||
enabled:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
state.enabled;
|
||||
status:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
if (state.enabled) "C"; else "B";
|
||||
maxcurrent:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
set();
|
||||
state.maxcurrent = val;
|
||||
if (state.enabled) state.chargepower = state.maxcurrent * 230;
|
||||
|
||||
vehicles:
|
||||
- name: demo
|
||||
title: e-Golf
|
||||
type: default
|
||||
charge:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
if (state.chargepower > 0) state.battery++; else state.battery--;
|
||||
if (state.battery < 15) state.battery = 15;
|
||||
if (state.battery > 100) state.battery = 100;
|
||||
state.battery;
|
||||
cache: 1s
|
||||
|
||||
site:
|
||||
title: Demo
|
||||
meters:
|
||||
grid: grid
|
||||
pv: pv
|
||||
battery: battery
|
||||
|
||||
loadpoints:
|
||||
- title: Carport
|
||||
charger: demo
|
||||
meters:
|
||||
charge: charge
|
||||
vehicle: demo
|
||||
`
|
||||
//go:embed demo.yaml
|
||||
var demoYaml string
|
||||
|
||||
func demoConfig() (conf config) {
|
||||
demo := map[string]interface{}{}
|
||||
|
|
|
|||
113
cmd/demo.yaml
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
log: info
|
||||
|
||||
javascript:
|
||||
- vm: shared
|
||||
script: |
|
||||
state = {
|
||||
residualpower: 200,
|
||||
pvpower: -3000,
|
||||
batterypower: 200,
|
||||
gridpower: -2000,
|
||||
chargepower: 0,
|
||||
maxcurrent: 0,
|
||||
battery: 63, // car
|
||||
};
|
||||
function get() {
|
||||
console.log("state:", JSON.stringify(state));
|
||||
}
|
||||
function set() {
|
||||
console.log(param+":", val);
|
||||
console.log("state:", JSON.stringify(state));
|
||||
}
|
||||
|
||||
meters:
|
||||
- name: grid
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.gridpower = state.pvpower + state.chargepower + state.residualpower + state.batterypower;
|
||||
|
||||
- name: pv
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.pvpower += 100*Math.random();
|
||||
|
||||
- name: battery
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.batterypower;
|
||||
soc:
|
||||
type: js
|
||||
vm: shared
|
||||
script: "30"
|
||||
- name: charge
|
||||
type: default
|
||||
power:
|
||||
type: js
|
||||
vm: shared
|
||||
script: state.chargepower;
|
||||
soc:
|
||||
type: js
|
||||
vm: shared
|
||||
script: "30"
|
||||
|
||||
chargers:
|
||||
- name: demo
|
||||
type: default
|
||||
enable:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
set();
|
||||
state.enabled = val;
|
||||
if (state.enabled) state.chargepower = state.maxcurrent * 230; else state.chargepower = 0;
|
||||
enabled:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
state.enabled;
|
||||
status:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
if (state.enabled) "C"; else "B";
|
||||
maxcurrent:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
set();
|
||||
state.maxcurrent = val;
|
||||
if (state.enabled) state.chargepower = state.maxcurrent * 230;
|
||||
|
||||
vehicles:
|
||||
- name: demo
|
||||
title: e-Golf
|
||||
type: default
|
||||
charge:
|
||||
type: js
|
||||
vm: shared
|
||||
script: |
|
||||
if (state.chargepower > 0) state.battery++; else state.battery--;
|
||||
if (state.battery < 15) state.battery = 15;
|
||||
if (state.battery > 100) state.battery = 100;
|
||||
state.battery;
|
||||
cache: 1s
|
||||
|
||||
site:
|
||||
title: Demo
|
||||
meters:
|
||||
grid: grid
|
||||
pv: pv
|
||||
battery: battery
|
||||
|
||||
loadpoints:
|
||||
- title: Carport
|
||||
charger: demo
|
||||
meters:
|
||||
charge: charge
|
||||
vehicle: demo
|
||||
6
dist/css/chunk-vendors.c5b0137c.css
vendored
Normal file
1
dist/css/index.4716cdc1.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.progress-bar-animated{animation-direction:reverse}.btn.caption{opacity:1}.btn.first{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}.value,input[type=radio],label.btn{white-space:nowrap!important}.text-muted a,.text-muted a:hover{color:#6c757d!important;text-decoration:none}.bg-muted{opacity:.25}.fade-enter-active[data-v-4b17e482],.fade-leave-active[data-v-4b17e482]{transition:opacity .25s ease-in}.fade-enter[data-v-4b17e482],.fade-leave-to[data-v-4b17e482]{opacity:0}.dialog[data-v-4b17e482]{position:fixed;top:0;left:0;z-index:1050;width:100%;height:100%;overflow:hidden;outline:0}.display-enter-active[data-v-4b17e482]{display:block!important}.expand-icon[data-v-4b17e482]{transition:transform .25s ease-in;transform:rotate(0)}.expand-icon-rotated[data-v-4b17e482]{transform:rotate(-180deg)}
|
||||
BIN
dist/ico/android-chrome-192x192.png
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
dist/ico/android-chrome-512x512.png
vendored
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
dist/ico/apple-touch-icon.png
vendored
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
9
dist/ico/browserconfig.xml
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="ico/mstile-150x150.png"/>
|
||||
<TileColor>#2b5797</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
BIN
dist/ico/favicon-16x16.png
vendored
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
dist/ico/favicon-32x32.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
dist/ico/favicon.ico
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
27
dist/ico/favicon.svg
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" viewBox="0 0 576 512" version="1.1" id="svg12"
|
||||
sodipodi:docname="leaf.svg" inkscape:version="1.0beta2 (2b71d25, 2019-12-03)">
|
||||
<metadata id="metadata18">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs16" />
|
||||
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" inkscape:document-rotation="0" borderopacity="1"
|
||||
objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2"
|
||||
inkscape:window-width="1280" inkscape:window-height="755" id="namedview14" showgrid="false"
|
||||
inkscape:zoom="0.92768596" inkscape:cx="353.312" inkscape:cy="200.09826" inkscape:window-x="0"
|
||||
inkscape:window-y="23" inkscape:window-maximized="0" inkscape:current-layer="svg12" />
|
||||
<path style="stroke-width:1.1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="M546.2 9.7c-5.6-12.5-21.6-13-28.3-1.2C486.9 62.4 431.4 96 368 96h-80C182 96 96 182 96 288c0 7 .8 13.7 1.5 20.5C161.3 262.8 253.4 224 384 224c8.8 0 16 7.2 16 16s-7.2 16-16 16C132.6 256 26 410.1 2.4 468c-6.6 16.3 1.2 34.9 17.5 41.6 16.4 6.8 35-1.1 41.8-17.3 1.5-3.6 20.9-47.9 71.9-90.6 32.4 43.9 94 85.8 174.9 77.2C465.5 467.5 576 326.7 576 154.3c0-50.2-10.8-102.2-29.8-144.6z"
|
||||
id="path10" />
|
||||
<path inkscape:connector-curvature="0" id="path20"
|
||||
d="m 21.21449,509.39751 c -5.971286,-2.52059 -9.269565,-4.81794 -12.9733928,-9.03637 -6.1766191,-7.03478 -8.8842152,-17.3518 -6.971629,-26.56467 1.258445,-6.0619 11.8107088,-27.39624 19.8175918,-40.06678 22.713423,-35.94297 56.773767,-71.44959 94.11207,-98.10823 68.76834,-49.09895 154.92997,-76.24193 249.47048,-78.5892 11.23532,-0.27896 21.89988,-0.8765 23.69902,-1.32786 4.02501,-1.0098 9.1941,-5.41782 10.76663,-9.18141 2.92101,-6.99096 0.29781,-15.90466 -5.87906,-19.97721 l -3.71288,-2.44799 -20.91224,0.12879 c -95.91234,0.59069 -191.38366,28.82528 -262.4752,77.62416 -4.25115,2.91809 -7.89194,5.14304 -8.090638,4.94433 -1.034492,-1.03449 -1.681776,-19.91176 -1.047227,-30.54108 4.946935,-82.86599 63.514115,-153.47981 144.215265,-173.87878 19.41459,-4.90746 20.47839,-4.979088 83.88455,-5.648034 49.15213,-0.518563 60.64802,-0.871339 68.23769,-2.09402 19.39657,-3.124747 35.56867,-8.269165 52.1562,-16.591125 29.26858,-14.684035 50.80653,-34.823142 71.56328,-66.915381 3.64477,-5.6352221 5.2829,-7.343539 8.63712,-9.0071805 5.61954,-2.78721054 10.73552,-2.07507421 15.40609,2.1445063 3.91499,3.5369576 8.97418,14.4546312 15.06776,32.5161072 20.64772,61.200058 24.79308,128.916947 11.83935,193.402597 -25.37559,126.32372 -112.033,220.27326 -224.43817,243.32443 -17.6222,3.61382 -29.64707,4.91447 -50.19768,5.42955 -21.4123,0.53668 -32.33232,-0.45528 -49.11375,-4.46143 -40.56718,-9.6844 -78.7741,-33.83895 -104.95018,-66.34986 l -5.80657,-7.21182 -7.6437,6.87084 c -26.141169,23.49803 -48.851538,52.36799 -61.996828,78.81184 -2.979862,5.99446 -6.952342,12.64221 -8.827734,14.77277 -7.841316,8.90821 -23.148129,12.54014 -33.836218,8.02851 z"
|
||||
style="fill:#007bff;stroke:#007bff;stroke-width:1.1;fill-opacity:1;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
BIN
dist/ico/mstile-150x150.png
vendored
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
47
dist/ico/safari-pinned-tab.svg
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="576.000000pt" height="576.000000pt"
|
||||
viewBox="0 0 576.000000 576.000000" preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,576.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">
|
||||
<path d="M5254 5426 c-30 -14 -94 -84 -94 -105 0 -6 -4 -11 -10 -11 -5 0 -10
|
||||
-4 -10 -10 0 -9 -64 -106 -80 -120 -3 -3 -21 -25 -40 -50 -147 -191 -344 -351
|
||||
-572 -466 -70 -35 -236 -103 -268 -109 -8 -2 -35 -9 -60 -16 -53 -15 -54 -15
|
||||
-100 -23 -19 -3 -46 -8 -60 -11 -55 -12 -115 -16 -330 -20 -124 -2 -227 -5
|
||||
-230 -6 -3 -1 -8 -1 -11 -1 -9 1 -102 2 -121 1 -10 0 -111 0 -225 0 -217 1
|
||||
-326 -3 -409 -14 -27 -4 -60 -8 -74 -9 -38 -5 -261 -63 -295 -77 -16 -7 -36
|
||||
-13 -43 -15 -26 -5 -147 -59 -232 -102 -258 -134 -488 -334 -672 -586 -21 -28
|
||||
-42 -57 -48 -63 -6 -7 -7 -13 -3 -13 4 0 3 -4 -3 -8 -13 -8 -71 -110 -118
|
||||
-209 -66 -137 -131 -333 -151 -453 -3 -19 -8 -46 -10 -60 -20 -105 -30 -283
|
||||
-21 -400 2 -25 4 -59 5 -77 1 -26 4 -30 20 -26 11 3 27 14 37 24 9 10 20 19
|
||||
24 19 4 0 36 19 71 43 90 60 168 107 173 104 2 -1 12 6 23 15 27 25 416 221
|
||||
463 233 3 1 16 6 30 12 171 73 503 184 620 208 8 2 15 4 15 5 0 2 21 7 60 15
|
||||
17 3 46 10 65 15 19 5 46 11 60 14 14 3 48 11 75 16 28 6 64 13 80 16 54 9 69
|
||||
11 110 18 23 3 52 9 65 11 28 5 89 13 250 31 129 14 341 25 549 27 137 2 152
|
||||
-1 193 -43 47 -48 57 -146 19 -196 -48 -65 -67 -69 -351 -78 -141 -5 -210 -9
|
||||
-335 -22 -33 -3 -76 -7 -95 -9 -19 -2 -51 -6 -70 -9 -19 -3 -57 -8 -84 -11
|
||||
-27 -3 -52 -8 -55 -9 -3 -2 -28 -6 -56 -10 -27 -3 -63 -9 -80 -12 -16 -4 -37
|
||||
-7 -45 -8 -9 -1 -21 -5 -28 -10 -6 -4 -12 -5 -12 -3 0 3 -37 -4 -82 -14 -46
|
||||
-11 -94 -22 -108 -25 -106 -22 -487 -144 -577 -185 -23 -10 -44 -19 -47 -19
|
||||
-22 0 -467 -220 -486 -240 -3 -3 -21 -14 -40 -24 -68 -37 -237 -150 -345 -231
|
||||
-236 -177 -480 -412 -653 -629 -31 -39 -60 -73 -63 -76 -4 -3 -50 -70 -103
|
||||
-149 -99 -148 -210 -356 -240 -448 -48 -147 25 -313 169 -383 41 -20 66 -24
|
||||
135 -25 75 0 92 4 144 30 71 36 115 85 168 190 137 272 288 476 530 715 53 52
|
||||
113 110 135 128 l38 33 18 -23 c91 -116 214 -241 320 -325 40 -32 74 -60 77
|
||||
-63 18 -19 249 -160 262 -160 5 0 22 -8 36 -18 35 -24 240 -105 295 -117 10
|
||||
-2 27 -7 37 -10 10 -3 28 -8 39 -10 12 -3 31 -7 44 -11 22 -5 47 -10 102 -19
|
||||
17 -3 41 -7 55 -10 14 -3 78 -7 143 -10 65 -3 121 -6 125 -6 4 -1 9 -1 12 0 3
|
||||
1 44 3 91 5 101 5 251 19 309 30 14 3 43 8 65 11 22 3 47 7 55 10 8 2 26 6 40
|
||||
9 85 14 355 97 447 137 24 10 44 18 46 18 13 -4 319 165 411 226 66 44 126 85
|
||||
135 90 8 6 24 18 35 27 12 10 55 46 96 80 114 95 261 243 365 369 44 53 155
|
||||
199 155 204 0 3 18 30 40 60 22 30 40 56 40 59 0 2 22 41 49 85 48 78 175 331
|
||||
201 401 7 19 17 39 22 44 4 6 8 16 8 24 0 8 6 28 14 45 15 34 28 70 27 75 -1
|
||||
1 6 19 15 40 8 20 17 44 19 52 2 8 13 49 25 90 24 82 57 209 64 249 3 14 7 37
|
||||
11 51 3 14 8 36 10 50 2 14 6 36 9 50 6 34 16 97 21 140 3 19 7 55 10 79 16
|
||||
121 19 198 19 446 -1 238 -4 308 -20 430 -2 17 -5 49 -8 72 -2 23 -7 55 -10
|
||||
70 -3 15 -8 48 -12 73 -3 24 -7 48 -10 51 -2 4 -6 24 -10 45 -19 130 -124 484
|
||||
-181 614 -57 130 -81 162 -130 181 -34 13 -82 11 -119 -5z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
20
dist/ico/site.webmanifest
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"start_url": "../",
|
||||
"name": "EV Charge Controller",
|
||||
"short_name": "EV Charge Controller",
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone",
|
||||
"icons": [
|
||||
{
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
4
dist/index.html
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg" color="#5bbad5"><link rel="shortcut icon" href="ico/favicon.ico"><meta name="msapplication-TileColor" content="#2b5797"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#ffffff"><title>evcc</title><link href="css/chunk-vendors.c5b0137c.css" rel="preload" as="style"><link href="css/index.4716cdc1.css" rel="preload" as="style"><link href="js/chunk-vendors.7c84295f.js" rel="preload" as="script"><link href="js/index.bf403928.js" rel="preload" as="script"><link href="css/chunk-vendors.c5b0137c.css" rel="stylesheet"><link href="css/index.4716cdc1.css" rel="stylesheet"></head><body><script>window.evcc = {
|
||||
version: "[[.Version]]",
|
||||
configured: "[[.Configured]]",
|
||||
};</script><div id="app"></div><div id="toasts"></div><footer class="pt-4 pb-2 pt-md-5 pb-md-4 mt-3 mt-md-5 border-top"><div class="container"><div class="row"><div class="col-6"><small class="text-muted"><a href="https://github.com/andig/evcc/releases/tag/[[.Version]]">[[.Version]]</a> (<a href="https://github.com/andig/evcc/commit/[[.Commit]]">[[.Commit]]</a>)</small></div><div class="col-6 text-right"><small class="text-muted">© 2020</small></div></div></div></footer><script src="js/chunk-vendors.7c84295f.js"></script><script src="js/index.bf403928.js"></script></body></html>
|
||||
78
dist/js/chunk-vendors.7c84295f.js
vendored
Normal file
1
dist/js/chunk-vendors.7c84295f.js.map
vendored
Normal file
2
dist/js/index.bf403928.js
vendored
Normal file
1
dist/js/index.bf403928.js.map
vendored
Normal file
|
|
@ -1,37 +1,52 @@
|
|||
############################
|
||||
# STEP 1 build executable binary
|
||||
############################
|
||||
FROM golang:1.14-alpine as builder
|
||||
# STEP 1 build ui
|
||||
FROM node:14-alpine as node
|
||||
|
||||
# Install git + SSL ca certificates.
|
||||
# Git is required for fetching the dependencies.
|
||||
# Ca-certificates is required to call HTTPS endpoints.
|
||||
RUN apk update && apk add --no-cache git ca-certificates tzdata alpine-sdk npm && update-ca-certificates
|
||||
RUN apk update && apk add --no-cache make
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# cache modules
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
RUN go mod download
|
||||
|
||||
# install go and node tools
|
||||
# install node tools
|
||||
COPY Makefile .
|
||||
COPY package*.json ./
|
||||
RUN make install
|
||||
RUN make install-ui
|
||||
|
||||
# build ui
|
||||
COPY assets assets
|
||||
COPY vue.config.js vue.config.js
|
||||
RUN make clean npm
|
||||
RUN make clean ui
|
||||
|
||||
|
||||
# STEP 2 build executable binary
|
||||
FROM golang:1.16-alpine as builder
|
||||
|
||||
# Install git + SSL ca certificates.
|
||||
# Git is required for fetching the dependencies.
|
||||
# Ca-certificates is required to call HTTPS endpoints.
|
||||
RUN apk update && apk add --no-cache git ca-certificates tzdata alpine-sdk && update-ca-certificates
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# install go tools and cache modules
|
||||
COPY Makefile .
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
RUN make install
|
||||
RUN go mod download
|
||||
|
||||
# prepare
|
||||
COPY . .
|
||||
RUN make assets
|
||||
|
||||
# copy ui
|
||||
COPY --from=node /build/dist /build/dist
|
||||
|
||||
# build
|
||||
COPY . .
|
||||
RUN make assets
|
||||
RUN GOARCH={{ .GoARCH }} GOARM={{ .GoARM }} make build
|
||||
|
||||
#############################
|
||||
## STEP 2 build a small image
|
||||
#############################
|
||||
|
||||
# STEP 3 build a small image including module support
|
||||
FROM {{ .RuntimeImage }}
|
||||
|
||||
ENV TZ=Europe/Berlin
|
||||
|
|
|
|||
3
go.mod
|
|
@ -1,6 +1,6 @@
|
|||
module github.com/andig/evcc
|
||||
|
||||
go 1.13
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.6.1
|
||||
|
|
@ -38,7 +38,6 @@ require (
|
|||
github.com/lorenzodonini/ocpp-go v0.12.1-0.20201122163044-c8e61b6f96d2
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
||||
github.com/mitchellh/mapstructure v1.4.1
|
||||
github.com/mjibson/esc v0.2.0
|
||||
github.com/muka/go-bluetooth v0.0.0-20201211051136-07f31c601d33
|
||||
github.com/mxschmitt/golang-combinations v1.1.0
|
||||
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da
|
||||
|
|
|
|||
2
go.sum
|
|
@ -137,7 +137,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
|
|||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ping/ping v0.0.0-20201022122018-3977ed72668a h1:O9xspHB2yrvKfMQ1m6OQhqe37i5yvg0dXAYMuAjugmM=
|
||||
github.com/go-ping/ping v0.0.0-20201022122018-3977ed72668a/go.mod h1:35JbSyV/BYqHwwRA6Zr1uVDm1637YlNOU61wI797NPI=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
|
|
@ -365,7 +364,6 @@ github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
|||
github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mjibson/esc v0.2.0 h1:k96hdaR9Z+nMcnDwNrOvhdBqtjyMrbVyxLpsRCdP2mA=
|
||||
github.com/mjibson/esc v0.2.0/go.mod h1:9Hw9gxxfHulMF5OJKCyhYD7PzlSdhzXyaGEBRPH1OPs=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
|
|
|
|||
20
main.go
|
|
@ -1,11 +1,27 @@
|
|||
package main
|
||||
|
||||
//go:generate esc -o server/assets.go -pkg server -modtime 1566640112 -ignore .DS_Store dist
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
|
||||
"github.com/andig/evcc/cmd"
|
||||
"github.com/andig/evcc/server"
|
||||
)
|
||||
|
||||
//go:embed dist
|
||||
var assets embed.FS
|
||||
|
||||
// init loads embedded assets unless live assets are already loaded
|
||||
func init() {
|
||||
if server.Assets == nil {
|
||||
fsys, err := fs.Sub(assets, "dist")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
server.Assets = fsys
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
||||
|
|
|
|||
15388
server/assets.go
|
|
@ -1,7 +0,0 @@
|
|||
// +build !release
|
||||
|
||||
package server
|
||||
|
||||
const (
|
||||
useLocalAssets = true
|
||||
)
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// +build release
|
||||
|
||||
package server
|
||||
|
||||
const (
|
||||
useLocalAssets = false
|
||||
)
|
||||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
|
@ -17,6 +18,9 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Assets is the embedded assets file system
|
||||
var Assets fs.FS
|
||||
|
||||
type chargeModeJSON struct {
|
||||
Mode api.ChargeMode `json:"mode"`
|
||||
}
|
||||
|
|
@ -49,17 +53,17 @@ func routeLogger(inner http.Handler) http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func indexHandler(site core.SiteAPI, useLocal bool) http.HandlerFunc {
|
||||
func indexHandler(site core.SiteAPI) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||
|
||||
indexTemplate, err := FSString(useLocal, "/dist/index.html")
|
||||
indexTemplate, err := fs.ReadFile(Assets, "index.html")
|
||||
if err != nil {
|
||||
log.FATAL.Print("httpd: failed to load embedded template:", err.Error())
|
||||
log.FATAL.Fatal("Make sure templates are included using the `release` build tag or use `make build`")
|
||||
}
|
||||
|
||||
t, err := template.New("evcc").Delims("[[", "]]").Parse(indexTemplate)
|
||||
t, err := template.New("evcc").Delims("[[", "]]").Parse(string(indexTemplate))
|
||||
if err != nil {
|
||||
log.FATAL.Fatal("httpd: failed to create main page template:", err.Error())
|
||||
}
|
||||
|
|
@ -220,7 +224,6 @@ func MinSoCHandler(loadpoint core.LoadPointAPI) http.HandlerFunc {
|
|||
}
|
||||
|
||||
if !ok || err != nil {
|
||||
log.DEBUG.Printf("parse soc: %v", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -338,15 +341,9 @@ func NewHTTPd(url string, site core.SiteAPI, hub *SocketHub, cache *util.Cache)
|
|||
static := router.PathPrefix("/").Subrouter()
|
||||
static.Use(handlers.CompressHandler)
|
||||
|
||||
static.HandleFunc("/", indexHandler(site, useLocalAssets))
|
||||
var distDir = Dir(false, "/dist/")
|
||||
if useLocalAssets {
|
||||
distDir = http.Dir("./dist")
|
||||
}
|
||||
for _, public := range []string{"css", "js", "ico"} {
|
||||
static.PathPrefix(fmt.Sprintf("/%s/", public)).Handler(
|
||||
http.Handler(http.FileServer(distDir)),
|
||||
)
|
||||
static.HandleFunc("/", indexHandler(site))
|
||||
for _, dir := range []string{"css", "js", "ico"} {
|
||||
static.PathPrefix("/" + dir).Handler(http.FileServer(http.FS(Assets)))
|
||||
}
|
||||
|
||||
// api
|
||||
|
|
|
|||
11
server/http_live.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// +build !release
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Assets = os.DirFS("dist")
|
||||
}
|
||||
1
tools.go
|
|
@ -4,5 +4,4 @@ package main
|
|||
|
||||
import (
|
||||
_ "github.com/golang/mock/mockgen"
|
||||
_ "github.com/mjibson/esc"
|
||||
)
|
||||
|
|
|
|||