Expand hints. Add RadioStatistics struct. Add new Order, DataAge and DataAgeMs.
This commit is contained in:
parent
163e3672ef
commit
851c6d01ec
2 changed files with 49 additions and 21 deletions
61
main.go
61
main.go
|
@ -72,20 +72,34 @@ type InverterINV struct {
|
||||||
YieldTotal VUD `json:"YieldTotal"`
|
YieldTotal VUD `json:"YieldTotal"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RadioStatistics contains radio communication statistics
|
||||||
|
type RadioStatistics struct {
|
||||||
|
TxRequest int `json:"tx_request"`
|
||||||
|
TxReRequest int `json:"tx_re_request"`
|
||||||
|
RxSuccess int `json:"rx_success"`
|
||||||
|
RxFailNothing int `json:"rx_fail_nothing"`
|
||||||
|
RxFailPartial int `json:"rx_fail_partial"`
|
||||||
|
RxFailCorrupt int `json:"rx_fail_corrupt"`
|
||||||
|
RSSI float64 `json:"rssi"`
|
||||||
|
}
|
||||||
|
|
||||||
// Inverter struct
|
// Inverter struct
|
||||||
type Inverter struct {
|
type Inverter struct {
|
||||||
Serial string `json:"serial"`
|
Serial string `json:"serial"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Order int `json:"order"`
|
||||||
|
DataAge int `json:"data_age"`
|
||||||
|
DataAgeMs int `json:"data_age_ms"`
|
||||||
Producing bool `json:"producing"`
|
Producing bool `json:"producing"`
|
||||||
LimitRelative float64 `json:"limit_relative"`
|
LimitRelative float64 `json:"limit_relative"`
|
||||||
LimitAbsolute float64 `json:"limit_absolute"`
|
LimitAbsolute float64 `json:"limit_absolute"`
|
||||||
AC map[string]InverterAC `json:"AC"`
|
|
||||||
DC map[string]InverterDC `json:"DC"`
|
|
||||||
Events int `json:"events"`
|
|
||||||
PollEnabled bool `json:"poll_enabled"`
|
PollEnabled bool `json:"poll_enabled"`
|
||||||
Reachable bool `json:"reachable"`
|
Reachable bool `json:"reachable"`
|
||||||
DataAge int `json:"data_age"`
|
Events int `json:"events"`
|
||||||
|
AC map[string]InverterAC `json:"AC"`
|
||||||
|
DC map[string]InverterDC `json:"DC"`
|
||||||
INV map[string]InverterINV `json:"INV"`
|
INV map[string]InverterINV `json:"INV"`
|
||||||
|
RadioStats RadioStatistics `json:"radio_stats"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Total struct {
|
type Total struct {
|
||||||
|
@ -98,6 +112,7 @@ type Hints struct {
|
||||||
TimeSync bool `json:"time_sync"`
|
TimeSync bool `json:"time_sync"`
|
||||||
RadioProblem bool `json:"radio_problem"`
|
RadioProblem bool `json:"radio_problem"`
|
||||||
DefaultPassword bool `json:"default_password"`
|
DefaultPassword bool `json:"default_password"`
|
||||||
|
PinMappingIssue bool `json:"pin_mapping_issue"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LiveData struct {
|
type LiveData struct {
|
||||||
|
@ -165,7 +180,7 @@ var config Config
|
||||||
|
|
||||||
// LoadConfig attempts to read the configuration from options.json
|
// LoadConfig attempts to read the configuration from options.json
|
||||||
// If it fails, it falls back to using environment variables
|
// If it fails, it falls back to using environment variables
|
||||||
func loadConfig() Config {
|
func loadConfig() (Config, error) {
|
||||||
configFilePath := os.Getenv("CONFIG_FILE")
|
configFilePath := os.Getenv("CONFIG_FILE")
|
||||||
if configFilePath == "" {
|
if configFilePath == "" {
|
||||||
configFilePath = "/data/options.json"
|
configFilePath = "/data/options.json"
|
||||||
|
@ -176,20 +191,20 @@ func loadConfig() Config {
|
||||||
// Successfully read the file, parse the JSON
|
// Successfully read the file, parse the JSON
|
||||||
err = json.Unmarshal(data, &config)
|
err = json.Unmarshal(data, &config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error parsing config file: %v", err)
|
return Config{}, fmt.Errorf("error parsing config file: %w", err)
|
||||||
}
|
}
|
||||||
if config.DB == "" {
|
if config.DB == "" {
|
||||||
log.Fatal("db connection settings are not set")
|
return Config{}, fmt.Errorf("db connection settings are not set")
|
||||||
}
|
}
|
||||||
if config.OpenDTUAddress == "" {
|
if config.OpenDTUAddress == "" {
|
||||||
log.Fatal("opendtu_address is not set")
|
return Config{}, fmt.Errorf("opendtu_address is not set")
|
||||||
}
|
}
|
||||||
if config.OpenDTUAuth {
|
if config.OpenDTUAuth {
|
||||||
if config.OpenDTUUser == "" {
|
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")
|
return Config{}, fmt.Errorf("opendtu_username is not set, while opendtu_auth is set to enabled. Set opendtu_auth to false or set username")
|
||||||
}
|
}
|
||||||
if config.OpenDTUPassword == "" {
|
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")
|
return Config{}, fmt.Errorf("opendtu_password is not set, while opendtu_auth is set to enabled. Set opendtu_auth to false or set password")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -197,29 +212,29 @@ func loadConfig() Config {
|
||||||
// Fallback to environment variables
|
// Fallback to environment variables
|
||||||
config.DB = os.Getenv("DB_URL")
|
config.DB = os.Getenv("DB_URL")
|
||||||
if config.DB == "" {
|
if config.DB == "" {
|
||||||
log.Fatal("DB_URL environment variable is not set.")
|
return Config{}, fmt.Errorf("DB_URL environment variable is not set")
|
||||||
}
|
}
|
||||||
config.OpenDTUAddress = os.Getenv("OPENDTU_ADDRESS")
|
config.OpenDTUAddress = os.Getenv("OPENDTU_ADDRESS")
|
||||||
if config.OpenDTUAddress == "" {
|
if config.OpenDTUAddress == "" {
|
||||||
log.Fatal("OPENDTU_ADDRESS environment variable is not set.")
|
return Config{}, fmt.Errorf("OPENDTU_ADDRESS environment variable is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
openDTUAuthStr := os.Getenv("OPENDTU_AUTH")
|
openDTUAuthStr := os.Getenv("OPENDTU_AUTH")
|
||||||
if openDTUAuthStr != "" {
|
if openDTUAuthStr != "" {
|
||||||
openDTUAuth, err := strconv.ParseBool(openDTUAuthStr)
|
openDTUAuth, err := strconv.ParseBool(openDTUAuthStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error parsing OPENDTU_AUTH: %v", err)
|
return Config{}, fmt.Errorf("error parsing OPENDTU_AUTH: %w", err)
|
||||||
}
|
}
|
||||||
config.OpenDTUAuth = openDTUAuth
|
config.OpenDTUAuth = openDTUAuth
|
||||||
}
|
}
|
||||||
if config.OpenDTUAuth {
|
if config.OpenDTUAuth {
|
||||||
config.OpenDTUUser = os.Getenv("OPENDTU_USERNAME")
|
config.OpenDTUUser = os.Getenv("OPENDTU_USERNAME")
|
||||||
if config.OpenDTUUser == "" {
|
if config.OpenDTUUser == "" {
|
||||||
log.Fatal("OPENDTU_USERNAME environment variable is not set.")
|
return Config{}, fmt.Errorf("OPENDTU_USERNAME environment variable is not set")
|
||||||
}
|
}
|
||||||
config.OpenDTUPassword = os.Getenv("OPENDTU_PASSWORD")
|
config.OpenDTUPassword = os.Getenv("OPENDTU_PASSWORD")
|
||||||
if config.OpenDTUPassword == "" {
|
if config.OpenDTUPassword == "" {
|
||||||
log.Fatal("OPENDTU_PASSWORD environment variable is not set.")
|
return Config{}, fmt.Errorf("OPENDTU_PASSWORD environment variable is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -228,7 +243,7 @@ func loadConfig() Config {
|
||||||
if timescaleDBStr != "" {
|
if timescaleDBStr != "" {
|
||||||
timescaleDB, err := strconv.ParseBool(timescaleDBStr)
|
timescaleDB, err := strconv.ParseBool(timescaleDBStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error parsing TIMESCALEDB_ENABLED: %v", err)
|
return Config{}, fmt.Errorf("error parsing TIMESCALEDB_ENABLED: %w", err)
|
||||||
}
|
}
|
||||||
config.TimescaleDB = timescaleDB
|
config.TimescaleDB = timescaleDB
|
||||||
}
|
}
|
||||||
|
@ -240,7 +255,7 @@ func loadConfig() Config {
|
||||||
logger.Warn("invalid timezone")
|
logger.Warn("invalid timezone")
|
||||||
}
|
}
|
||||||
|
|
||||||
return config
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to map environment variable to slog.Level
|
// Helper function to map environment variable to slog.Level
|
||||||
|
@ -273,7 +288,11 @@ func main() {
|
||||||
slog.SetDefault(logger)
|
slog.SetDefault(logger)
|
||||||
|
|
||||||
// Load the configuration
|
// Load the configuration
|
||||||
config := loadConfig()
|
var err error
|
||||||
|
config, err = loadConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Set the logLevel
|
// Set the logLevel
|
||||||
logLevel := getLogLevel(slog.LevelInfo) // Default to info level
|
logLevel := getLogLevel(slog.LevelInfo) // Default to info level
|
||||||
|
@ -468,9 +487,9 @@ func insertLiveData(db *sql.DB, inverter Inverter, total Total, hints Hints) {
|
||||||
}
|
}
|
||||||
// Insert data into hints table
|
// Insert data into hints table
|
||||||
_, err = db.Exec(`
|
_, err = db.Exec(`
|
||||||
INSERT INTO opendtu_hints (timestamp, time_sync, radio_problem, default_password)
|
INSERT INTO opendtu_hints (timestamp, time_sync, radio_problem, default_password, pin_mapping_issue)
|
||||||
VALUES ($1, $2, $3, $4);
|
VALUES ($1, $2, $3, $4, $5);
|
||||||
`, timestamp, hints.TimeSync, hints.RadioProblem, hints.DefaultPassword)
|
`, timestamp, hints.TimeSync, hints.RadioProblem, hints.DefaultPassword, hints.PinMappingIssue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Error inserting into log table", "error", err)
|
logger.Error("Error inserting into log table", "error", err)
|
||||||
return
|
return
|
||||||
|
|
9
migrations/00009_hints_pin_mapping.sql
Normal file
9
migrations/00009_hints_pin_mapping.sql
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE opendtu_hints ADD COLUMN IF NOT EXISTS pin_mapping_issue BOOLEAN NOT NULL DEFAULT FALSE;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE opendtu_hints DROP COLUMN IF EXISTS pin_mapping_issue;
|
||||||
|
-- +goose StatementEnd
|
Loading…
Add table
Add a link
Reference in a new issue