47 lines
1.8 KiB
TypeScript
47 lines
1.8 KiB
TypeScript
import { config as loadDotenv } from "dotenv";
|
|
import { fileURLToPath } from "node:url";
|
|
import { dirname, join } from "node:path";
|
|
import { z } from "zod";
|
|
|
|
// In production (docker-compose) env vars are already injected via env_file;
|
|
// this only fills gaps for local `npm run dev`, and is a no-op if the file is absent.
|
|
loadDotenv({ path: join(dirname(fileURLToPath(import.meta.url)), "../../.env") });
|
|
|
|
const envSchema = z.object({
|
|
PORT: z.coerce.number().default(3000),
|
|
INFLUX_URL: z.string().url(),
|
|
INFLUX_TOKEN: z.string().min(1),
|
|
INFLUX_ORG: z.string().min(1),
|
|
INFLUX_BUCKET: z.string().min(1),
|
|
INFLUX_MEASUREMENT: z.string().default("power"),
|
|
INFLUX_DOMAIN: z.string(),
|
|
INFLUX_ENTITY_ID: z.string(),
|
|
INFLUX_FIELD: z.string().default("value"),
|
|
INFLUX_FIELD_UNIT: z.enum(["W", "kW"]).default("W"),
|
|
HA_URL: z.string().url(),
|
|
HA_TOKEN: z.string().min(1),
|
|
// Solar inverter production, read from InfluxDB (same shape as the house
|
|
// power series above). Leave SOLAR_INFLUX_ENTITY_ID unset to fall back to
|
|
// sun.sun (astronomical day/night).
|
|
SOLAR_INFLUX_MEASUREMENT: z.string().default("power"),
|
|
SOLAR_INFLUX_DOMAIN: z.string().optional(),
|
|
SOLAR_INFLUX_ENTITY_ID: z.string().optional(),
|
|
SOLAR_INFLUX_FIELD: z.string().default("value"),
|
|
SOLAR_INFLUX_FIELD_UNIT: z.enum(["W", "kW"]).default("W"),
|
|
SOLAR_PRODUCTION_THRESHOLD_W: z.coerce.number().default(50),
|
|
TARGET_KW: z.coerce.number().positive(),
|
|
DB_PATH: z.string().default("./data/energy.db"),
|
|
CONTROL_LOOP_INTERVAL_MS: z.coerce.number().default(10_000),
|
|
});
|
|
|
|
export type Env = z.infer<typeof envSchema>;
|
|
|
|
export function loadEnv(): Env {
|
|
const parsed = envSchema.safeParse(process.env);
|
|
if (!parsed.success) {
|
|
console.error("Invalid environment configuration:", parsed.error.flatten().fieldErrors);
|
|
process.exit(1);
|
|
}
|
|
return parsed.data;
|
|
}
|