Turns out HomeAssistant only returns 10 days'data byault. This is a problem that we will havsoon. Now the cache doesn't reset eh time it only if some data is missing.
131 lines
3.2 KiB
Go
Executable file
131 lines
3.2 KiB
Go
Executable file
package main
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/gofiber/fiber/v2"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Config struct {
|
|
db *sql.DB
|
|
HomeAssistant HomeAssistant `json:"home_assistant"`
|
|
Sensors Sensors `json:"sensors"`
|
|
Administrator Administrator `json:"administrator"`
|
|
Dashboard Dashboard `json:"dashboard"`
|
|
}
|
|
|
|
type HomeAssistant struct {
|
|
BaseURL string `json:"base_url"`
|
|
ApiKey string `json:"api_key"`
|
|
InstallationDate time.Time `json:"installation_date"`
|
|
}
|
|
type Sensors struct {
|
|
PolledSmartEnergySummation string `json:"polled_smart_energy_summation"`
|
|
FossilPercentage string `json:"fossil_percentage"`
|
|
}
|
|
type Administrator struct {
|
|
Username string `json:"username"`
|
|
PasswordHash string `json:"password_hash"`
|
|
}
|
|
type Dashboard struct {
|
|
Name string `json:"name"`
|
|
Theme string `json:"theme"`
|
|
FooterLinks []Link `json:"footer_links"`
|
|
HeaderLinks []Link `json:"header_links"`
|
|
}
|
|
|
|
func formatURL(url string) (string, error) {
|
|
|
|
// the URL we want is: protocol://hostname[:port] without a final /
|
|
|
|
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
|
|
url = "http://" + url
|
|
}
|
|
if strings.HasSuffix(url, "/") {
|
|
url = url[0 : len(url)-1]
|
|
}
|
|
|
|
test := regexp.MustCompile(`(?m)https?:\/\/[^/]*`).ReplaceAllString(url, "")
|
|
if test != "" {
|
|
return "", errors.New("HomeAssistant base URL is badly formatted")
|
|
}
|
|
|
|
return url, nil
|
|
|
|
}
|
|
|
|
func loadConfig() (config Config, err error, isFirstRun bool) {
|
|
|
|
var defaultConfig = Config{}
|
|
defaultConfig.Dashboard.Theme = "default"
|
|
defaultConfig.Dashboard.Name = "EcoDash"
|
|
defaultConfig.Dashboard.HeaderLinks = append(defaultConfig.Dashboard.HeaderLinks, Link{
|
|
Label: "Admin",
|
|
Destination: "/admin",
|
|
}, Link{
|
|
Label: "Docs",
|
|
Destination: "https://gitea.massivebox.net/massivebox/ecodash",
|
|
NewTab: true,
|
|
Primary: true,
|
|
})
|
|
|
|
data, err := os.ReadFile("config.json")
|
|
if err != nil {
|
|
// if the data file doesn't exist, we consider it a first run
|
|
if os.IsNotExist(err) {
|
|
return defaultConfig, nil, true
|
|
}
|
|
return Config{}, err, false
|
|
}
|
|
|
|
// if the data file is empty, we consider it as a first run
|
|
if string(data) == "" {
|
|
return defaultConfig, nil, true
|
|
}
|
|
|
|
var conf Config
|
|
err = json.Unmarshal(data, &conf)
|
|
if err != nil {
|
|
return Config{}, err, false
|
|
}
|
|
|
|
db, err := sql.Open("sqlite3", "./database.db")
|
|
if err != nil {
|
|
return Config{}, err, false
|
|
}
|
|
conf.db = db
|
|
|
|
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS "cache" (
|
|
"time" NUMERIC NOT NULL,
|
|
"green_energy_percentage" REAL NOT NULL,
|
|
"energy_consumption" REAL NOT NULL,
|
|
PRIMARY KEY("time")
|
|
);`)
|
|
if err != nil {
|
|
return Config{}, err, false
|
|
}
|
|
|
|
return conf, nil, false
|
|
|
|
}
|
|
|
|
// just a little utility function to SHA256 strings (for hashing passwords)
|
|
func hash(toHash string) string {
|
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(toHash)))
|
|
}
|
|
|
|
func (config Config) isAuthorized(c *fiber.Ctx) bool {
|
|
if config.Administrator.PasswordHash == "" {
|
|
return true
|
|
}
|
|
return c.Cookies("admin_username") == config.Administrator.Username && c.Cookies("admin_password_hash") == config.Administrator.PasswordHash
|
|
}
|