Compare commits

...

14 commits

Author SHA1 Message Date
40abe7309d
Add note about OpenDTU version compatibility
All checks were successful
Build Docker image / build (push) Successful in 2m31s
Build Golang packages / release (push) Has been skipped
2025-01-17 12:40:34 +01:00
50d89748f7
go mod tidy
All checks were successful
Build Docker image / build (push) Successful in 3m8s
Build Golang packages / release (push) Has been skipped
2024-09-14 18:16:13 +02:00
dc6f41eeb0
Update go dependencies. 2024-09-14 18:15:52 +02:00
0052a9848b
go mod tidy
All checks were successful
Build Docker image / build (push) Successful in 2m16s
Build Golang packages / release (push) Has been skipped
2024-08-14 23:18:54 +02:00
626b7f9993
Update Go 1.22 -> 1.23
All checks were successful
Build Docker image / build (push) Successful in 2m17s
Build Golang packages / release (push) Has been skipped
2024-08-14 19:34:59 +02:00
ed1b6d69ec
Go dependency upgrades
All checks were successful
Build Docker image / build (push) Successful in 3m44s
Build Golang packages / release (push) Has been skipped
2024-08-10 23:42:38 +02:00
c8b8211e3a
Add documentation for ARG TARGET* 2024-08-10 09:54:57 +02:00
ce336b4f85
Make go build TARGETOS configurable.
All checks were successful
Build Docker image / build (push) Successful in 2m16s
Build Golang packages / release (push) Successful in 2m1s
2024-08-08 11:19:01 +02:00
b8ea94bb61
Add TARGETOS and TARGETARCH to fix multi-platform compilation issue.
Some checks failed
Build Golang packages / release (push) Waiting to run
Build Docker image / build (push) Has been cancelled
2024-08-08 11:18:26 +02:00
014a5e85a2
Fix to take into account user-defined timezone for insertEvents. Add multi OpenDTU TODO. 2024-08-07 18:55:26 +02:00
32bebfdca2
Add default admin user to OPENDTU_USERNAME
All checks were successful
Build Docker image / build (push) Successful in 1m12s
Build Golang packages / release (push) Successful in 2m16s
2024-07-27 00:43:29 +02:00
3556e401bc
Add configurable LOG_LEVEL env vars.
Some checks failed
Build Golang packages / release (push) Waiting to run
Build Docker image / build (push) Has been cancelled
2024-07-27 00:42:51 +02:00
b63c1e85d3
Add DEBUG log_level.
All checks were successful
Build Docker image / build (push) Successful in 1m35s
Build Golang packages / release (push) Successful in 2m4s
2024-07-27 00:08:40 +02:00
48d0382b0e
BREAKING: Migrate REMOTE_URL to OPENDTU_ADDRESS.
All checks were successful
Build Docker image / build (push) Successful in 1m12s
Build Golang packages / release (push) Successful in 2m4s
BREAKING: Migrate opendtu to opendtu_address
Add authentication capability for locked-down opendtu's.
Updated setup examples with new variables.
2024-07-26 23:46:19 +02:00
11 changed files with 188 additions and 49 deletions

View file

@ -1,5 +1,5 @@
# Use buildx for multi-architecture support
FROM --platform=${BUILDPLATFORM} golang:1.22 AS builder
FROM --platform=${BUILDPLATFORM} golang:1.23 AS builder
WORKDIR /app
@ -11,7 +11,10 @@ RUN go mod download
COPY . .
# Build the application for the specified target architecture
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} go build -o opendtu-logger .
# https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/
# Declare TARGETOS and TARGETARCH in the local scope so they can be used in the build stage.
ARG TARGETOS TARGETARCH
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o opendtu-logger .
# Create a minimal runtime image
FROM --platform=${TARGETPLATFORM} scratch

View file

@ -25,6 +25,7 @@ Installation on Home Assistant can be done by adding the [Home Assistant add-on
### Configuring OpenDTU
In order for OpenDTU Logger to work properly, it is required to ensure the following OpenDTU settings are used.
OpenDTU Logger 0.1.3 has been tested with OpenDTU versions v24.6.10 - v25.1.14.
- Within OpenDTU, go to `Settings` -> `Inverter settings` (<http://YOUR_OPENDTU_IP_ADDRESS/settings/inverter>).
- For each inverter in the inverter list, click on the pencil (Edit inverter) and go to `Advanced`.

View file

@ -26,9 +26,13 @@ services:
restart: always
environment:
DB_URL: ${DB_URL}
REMOTE_URL: ${REMOTE_URL}
OPENDTU_ADDRESS: ${OPENDTU_ADDRESS}
OPENDTU_AUTH: ${OPENDTU_AUTH}
OPENDTU_USERNAME: ${OPENDTU_USERNAME}
OPENDTU_PASSWORD: ${OPENDTU_PASSWORD}
TIMESCALEDB_ENABLED: ${TIMESCALEDB_ENABLED}
TZ: ${TZ}
LOG_LEVEL: ${LOG_LEVEL}
depends_on:
timescaledb:
condition: service_healthy

View file

@ -26,9 +26,14 @@ services:
image: git.hollander.online/energy/opendtu-logger:latest
environment:
DB_URL: ${DB_URL}
REMOTE_URL: ${REMOTE_URL}
OPENDTU_ADDRESS: ${OPENDTU_ADDRESS}
OPENDTU_AUTH: ${OPENDTU_AUTH}
OPENDTU_USERNAME: ${OPENDTU_USERNAME}
OPENDTU_PASSWORD: ${OPENDTU_PASSWORD}
TIMESCALEDB_ENABLED: ${TIMESCALEDB_ENABLED}
TZ: ${TZ}
LOG_LEVEL: ${LOG_LEVEL}
depends_on:
timescaledb:
condition: service_healthy

View file

@ -5,9 +5,13 @@ services:
image: git.hollander.online/energy/opendtu-logger:latest
environment:
DB_URL: ${DB_URL}
REMOTE_URL: ${REMOTE_URL}
OPENDTU_ADDRESS: ${OPENDTU_ADDRESS}
OPENDTU_AUTH: ${OPENDTU_AUTH}
OPENDTU_USERNAME: ${OPENDTU_USERNAME}
OPENDTU_PASSWORD: ${OPENDTU_PASSWORD}
TIMESCALEDB_ENABLED: ${TIMESCALEDB_ENABLED}
TZ: ${TZ}
LOG_LEVEL: ${LOG_LEVEL}
depends_on:
timescaledb:
condition: service_healthy

11
docker/example.env Normal file
View file

@ -0,0 +1,11 @@
# OpenDTU
OPENDTU_ADDRESS="192.168.1.89:80"
OPENDTU_AUTH=false
OPENDTU_USERNAME=admin
OPENDTU_PASSWORD=
# OpenDTU Logger
DB_URL="host=timescaledb port=5432 user=postgres password=secret dbname=opendtu_logger sslmode=disable"
TIMESCALEDB_ENABLED=true
TZ="Europe/Amsterdam"
LOG_LEVEL=INFO"

View file

@ -1,9 +1,16 @@
# OpenDTU
OPENDTU_ADDRESS="192.168.1.89:80"
OPENDTU_AUTH=false
OPENDTU_USERNAME=admin
OPENDTU_PASSWORD=
# OpenDTU Logger
REMOTE_URL="192.168.1.89:80"
DB_URL="host=timescaledb port=5432 user=postgres password=secret dbname=opendtu_logger sslmode=disable"
TIMESCALEDB_ENABLED=true
TZ="Europe/Amsterdam"
LOG_LEVEL=INFO"
# Database configuration
PG_USER=postgres
PG_PASSWORD=
PG_DB=opendtu_logger
PG_DB=opendtu_logger

9
go.mod
View file

@ -1,17 +1,16 @@
module git.hollander.online/energy/opendtu-logger
go 1.22
go 1.23
require (
github.com/gorilla/websocket v1.5.3
github.com/lib/pq v1.10.9
github.com/pressly/goose/v3 v3.21.1
github.com/pressly/goose/v3 v3.22.0
)
require (
github.com/mfridman/interpolate v0.0.2 // indirect
github.com/sethvargo/go-retry v0.2.4 // indirect
github.com/sethvargo/go-retry v0.3.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sync v0.8.0 // indirect
)

33
go.sum
View file

@ -4,8 +4,6 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@ -20,37 +18,32 @@ github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdh
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pressly/goose/v3 v3.21.1 h1:5SSAKKWej8LVVzNLuT6KIvP1eFDuPvxa+B6H0w78buQ=
github.com/pressly/goose/v3 v3.21.1/go.mod h1:sqthmzV8PitchEkjecFJII//l43dLOCzfWh8pHEe+vE=
github.com/pressly/goose/v3 v3.22.0 h1:wd/7kNiPTuNAztWun7iaB98DrhulbWPrzMAaw2DEZNw=
github.com/pressly/goose/v3 v3.22.0/go.mod h1:yJM3qwSj2pp7aAaCvso096sguezamNb2OBgxCnh/EYg=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/sqlite v1.29.6 h1:0lOXGrycJPptfHDuohfYgNqoe4hu+gYuN/pKgY5XjS4=
modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s=
modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

139
main.go
View file

@ -1,14 +1,15 @@
// TODO: Storage optimisation: Map inverter serial to shorter serial. Use that for referring.
// TODO: Use username and password provided using Basic Authentication.
// TODO: Record Inverter struct data only on-change.
// Idea: Make a full admin / config GUI and only configure through this utility.
// Idea: Gather settings only on start-up.
// TODO: Only update meter readings such as yieldday, yieldtotal on-change.
// TODO: Add a health check endpoint, potentially log to it.
// TODO: Add support for monitoring multiple OpenDTU's at once.
package main
import (
"database/sql"
"encoding/base64"
"encoding/json"
"fmt"
"io/fs"
@ -149,10 +150,14 @@ type InverterSettingsData struct {
// Config settings struct
type Config struct {
DB string `json:"db"`
OpenDTU string `json:"opendtu"`
TimescaleDB bool `json:"timescaledb"`
TZ string `json:"tz"`
DB string `json:"db"`
OpenDTUAddress string `json:"opendtu_address"`
OpenDTUAuth bool `json:"opendtu_auth"`
OpenDTUUser string `json:"opendtu_username"`
OpenDTUPassword string `json:"opendtu_password"`
TimescaleDB bool `json:"timescaledb"`
TZ string `json:"tz"`
LogLevel string `json:"log_level"`
}
var logger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
@ -173,15 +178,50 @@ func loadConfig() Config {
if err != nil {
log.Fatalf("Error parsing config file: %v", err)
}
if config.DB == "" {
log.Fatal("db connection settings are not set")
}
if config.OpenDTUAddress == "" {
log.Fatal("opendtu_address is not set")
}
if config.OpenDTUAuth {
if config.OpenDTUUser == "" {
log.Fatal("opendtu_username is not set, while opendtu_auth is set to enabled. Set opendtu_auth to false or set username")
}
if config.OpenDTUPassword == "" {
log.Fatal("opendtu_password is not set, while opendtu_auth is set to enabled. Set opendtu_auth to false or set password")
}
}
} else {
logger.Info("JSON config file not found. Falling back to environment variables.")
// Fallback to environment variables
config.DB = os.Getenv("DB_URL")
if config.DB == "" {
log.Fatal("DB_URL environment variable is not set.")
}
config.OpenDTU = os.Getenv("REMOTE_URL")
if config.OpenDTU == "" {
log.Fatal("REMOTE_URL environment variable is not set.")
config.OpenDTUAddress = os.Getenv("OPENDTU_ADDRESS")
if config.OpenDTUAddress == "" {
log.Fatal("OPENDTU_ADDRESS environment variable is not set.")
}
openDTUAuthStr := os.Getenv("OPENDTU_AUTH")
if openDTUAuthStr != "" {
openDTUAuth, err := strconv.ParseBool(openDTUAuthStr)
if err != nil {
log.Fatalf("Error parsing OPENDTU_AUTH: %v", err)
}
config.OpenDTUAuth = openDTUAuth
}
if config.OpenDTUAuth {
config.OpenDTUUser = os.Getenv("OPENDTU_USERNAME")
if config.OpenDTUUser == "" {
log.Fatal("OPENDTU_USERNAME environment variable is not set.")
}
config.OpenDTUPassword = os.Getenv("OPENDTU_PASSWORD")
if config.OpenDTUPassword == "" {
log.Fatal("OPENDTU_PASSWORD environment variable is not set.")
}
}
timescaleDBStr := os.Getenv("TIMESCALEDB_ENABLED")
@ -193,11 +233,40 @@ func loadConfig() Config {
config.TimescaleDB = timescaleDB
}
config.TZ = os.Getenv("TZ")
config.LogLevel = os.Getenv("LOG_LEVEL")
}
_, err = time.LoadLocation(config.TZ)
if err != nil {
logger.Warn("invalid timezone")
}
return config
}
// Helper function to map environment variable to slog.Level
func getLogLevel(defaultLevel slog.Level) slog.Level {
logLevelStr := config.LogLevel
switch logLevelStr {
case "DEBUG":
return slog.LevelDebug
case "INFO":
return slog.LevelInfo
case "WARN":
return slog.LevelWarn
case "ERROR":
return slog.LevelError
default:
return defaultLevel
}
}
// Function to create a new logger with a specified log level
func createLoggerWithLevel(level slog.Level) *slog.Logger {
return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: level,
}))
}
// Main program
func main() {
// Initial logger setup
@ -206,6 +275,10 @@ func main() {
// Load the configuration
config := loadConfig()
// Set the logLevel
logLevel := getLogLevel(slog.LevelInfo) // Default to info level
logger = createLoggerWithLevel(logLevel)
dbConnStr := config.DB
// Connect to PostgreSQL
db, err := sql.Open("postgres", dbConnStr)
@ -218,10 +291,18 @@ func main() {
migrateDB(db)
// Create WebSocket URL from config variable
wsURL := "ws://" + config.OpenDTU + "/livedata"
wsURL := "ws://" + config.OpenDTUAddress + "/livedata"
logger.Debug(wsURL)
// Create headers with optional Basic Auth
headers := http.Header{}
if config.OpenDTUAuth {
headers.Set("Authorization", basicAuth(config.OpenDTUUser, config.OpenDTUPassword))
}
// Establish WebSocket connection
c, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
c, _, err := websocket.DefaultDialer.Dial(wsURL, headers)
if err != nil {
log.Fatal(err)
}
@ -424,15 +505,33 @@ func migrateFS(db *sql.DB, migrationFS fs.FS, dir string) error {
}
func queryEventsEndpoint(inverterSerial string) (*EventsResponse, error) {
remoteURL := config.OpenDTU
endpoint := fmt.Sprintf("http://"+remoteURL+"/api/eventlog/status?inv=%s", inverterSerial)
endpoint := fmt.Sprintf("http://"+config.OpenDTUAddress+"/api/eventlog/status?inv=%s", inverterSerial)
resp, err := http.Get(endpoint)
// Create a new HTTP request
req, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
return nil, err
}
if config.OpenDTUAuth {
// Add Basic Auth header
req.Header.Add("Authorization", basicAuth(config.OpenDTUUser, config.OpenDTUPassword))
}
// Send the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// Check for HTTP errors
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP request failed with status: %s", resp.Status)
}
// Decode the response
var eventsResponse EventsResponse
if err := json.NewDecoder(resp.Body).Decode(&eventsResponse); err != nil {
return nil, err
@ -465,7 +564,9 @@ func getPreviousEventsCount(db *sql.DB, inverterSerial string) int {
}
func insertEvents(db *sql.DB, inverterSerial string, events *EventsResponse) {
timestamp := time.Now()
timeZone := config.TZ
loc, _ := time.LoadLocation(timeZone)
timestamp := time.Now().In(loc)
for _, event := range events.Events {
// Insert events data into the events table
@ -508,6 +609,12 @@ func updateEvents(db *sql.DB, inverterSerial string, events *EventsResponse) {
}
}
// basicAuth generates the Basic Auth header value
func basicAuth(username, password string) string {
credentials := username + ":" + password
return "Basic " + base64.StdEncoding.EncodeToString([]byte(credentials))
}
// TODO: finish this function.
// func updateInverterConfig(db *sql.DB) {
// // Periodically query the /api/inverter/list
@ -526,8 +633,8 @@ func updateEvents(db *sql.DB, inverterSerial string, events *EventsResponse) {
// }
// func queryConfigEndpoint() (*InverterSettingsData, error) {
// remoteURL := os.Getenv("REMOTE_URL")
// endpoint := fmt.Sprintf("http://" + remoteURL + "/api/inverter/list")
// openDTUAddress := os.Getenv("OPENDTU_ADDRESS")
// endpoint := fmt.Sprintf("http://" + openDTUAddress + "/api/inverter/list")
// resp, err := http.Get(endpoint)
// if err != nil {

View file

@ -16,10 +16,15 @@ Type=simple
User=opendtu-logger
Group=opendtu-logger
Environment="REMOTE_URL=opendtu.local:80"
Environment="OPENDTU_ADDRESS=opendtu.local:80"
Environment="OPENDTU_AUTH=false"
Environment="OPENDTU_USERNAME=admin"
Environment="OPENDTU_PASSWORD=your_super_secret_password"
Environment="DB_URL=host=localhost port=5432 user=postgres password=secret dbname=dtu sslmode=disable"
Environment="TIMESCALEDB_ENABLED=true"
Environment="TZ=Europe/Amsterdam"
Environment="LOG_LEVEL=INFO"
WorkingDirectory=/opt/opendtu-logger/
ExecStart=/opt/opendtu-logger/opendtu-logger