All checks were successful
CI / changes (push) Successful in 19s
CI / test (push) Successful in 24s
CI / build-ai-gateway (push) Successful in 1m6s
CI / build-ha-gateway (push) Successful in 1m3s
CI / build-discord-bot (push) Successful in 1m4s
CI / build-alexa-bridge (push) Successful in 1m15s
CI / build-tts-gateway (push) Successful in 1m5s
CI / build-tts-sidecar (push) Has been skipped
CI / build-tts-model (push) Has been skipped
- Implemented SetTemperature in ClimateService for setting an absolute target temperature. - Updated ClimateServiceClient and ClimateServiceServer interfaces to include SetTemperature. - Added corresponding handler and tests for SetTemperature in ClimateGRPC. - Modified ClimateApp to handle SetTemperature requests without clamping. - Updated climate.proto to define SetTemperatureRequest message. - Adjusted Dockerfiles to include alexa-bridge dependencies.
87 lines
2.9 KiB
Go
87 lines
2.9 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// Config holds runtime configuration for the alexa-bridge process.
|
|
type Config struct {
|
|
HTTPPort string // HTTP_PORT, default "8080"
|
|
AlexaSkillID string // ALEXA_SKILL_ID — verified against the request envelope's application ID (required)
|
|
HAGatewayAddr string // HA_GATEWAY_ADDR, default "ha-gateway.home-services.svc.cluster.local:50051"
|
|
HAGatewayServerName string // HA_GATEWAY_SERVER_NAME, default "ha-gateway.home-services.svc.cluster.local"
|
|
TLSDir string // TLS_DIR, default "/tls" — unlike ai-gateway/discord-bot, mTLS is on by default here since alexa-bridge is internet-facing; set empty to disable for local dev
|
|
EntityRefreshInterval time.Duration // ENTITY_REFRESH_INTERVAL, default 5m
|
|
OTELEndpoint string // OTEL_ENDPOINT, empty disables telemetry
|
|
LogLevel string // LOG_LEVEL, default "info"
|
|
LogFormat string // LOG_FORMAT, default "json"
|
|
}
|
|
|
|
// Load reads configuration from environment variables and applies defaults.
|
|
func Load() (*Config, error) {
|
|
skillID := os.Getenv("ALEXA_SKILL_ID")
|
|
if skillID == "" {
|
|
return nil, errors.New("ALEXA_SKILL_ID is required but not set")
|
|
}
|
|
|
|
refreshInterval, err := parseDurationEnv("ENTITY_REFRESH_INTERVAL", 5*time.Minute)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cfg := &Config{
|
|
HTTPPort: getenvDefault("HTTP_PORT", "8080"),
|
|
AlexaSkillID: skillID,
|
|
HAGatewayAddr: getenvDefault("HA_GATEWAY_ADDR", "ha-gateway.home-services.svc.cluster.local:50051"),
|
|
HAGatewayServerName: getenvDefault("HA_GATEWAY_SERVER_NAME", "ha-gateway.home-services.svc.cluster.local"),
|
|
TLSDir: getenvDefault("TLS_DIR", "/tls"),
|
|
EntityRefreshInterval: refreshInterval,
|
|
OTELEndpoint: os.Getenv("OTEL_ENDPOINT"),
|
|
LogLevel: getenvDefault("LOG_LEVEL", "info"),
|
|
LogFormat: getenvDefault("LOG_FORMAT", "json"),
|
|
}
|
|
if cfg.TLSDir != "" {
|
|
if err := validateTLSDir(cfg.TLSDir); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return cfg, nil
|
|
}
|
|
|
|
func getenvDefault(key, fallback string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func parseDurationEnv(key string, fallback time.Duration) (time.Duration, error) {
|
|
if v := os.Getenv(key); v != "" {
|
|
d, err := time.ParseDuration(v)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("parse %s: %w", key, err)
|
|
}
|
|
return d, nil
|
|
}
|
|
return fallback, nil
|
|
}
|
|
|
|
func validateTLSDir(dir string) error {
|
|
required := []string{"tls.crt", "tls.key", "ca.crt"}
|
|
for _, name := range required {
|
|
path := filepath.Join(dir, name)
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return fmt.Errorf("tls dir validation failed for %s: %w", path, err)
|
|
}
|
|
if info.IsDir() {
|
|
return fmt.Errorf("tls dir validation failed for %s: %w", path, errors.New("expected file"))
|
|
}
|
|
}
|
|
return nil
|
|
}
|