fix: various fixes

This commit is contained in:
Willem Serruys
2026-08-21 11:49:49 +02:00
parent 161b226db9
commit 43fda71c1b
10 changed files with 441 additions and 185 deletions

View File

@@ -2,27 +2,40 @@ import type { QueryApi } from "@influxdata/influxdb-client";
import type { Env } from "../env.js";
import type { PowerSample } from "../types.js";
interface SeriesConfig {
bucket: string;
measurement: string;
field: string;
fieldUnit: "W" | "kW";
domain?: string;
entityId?: string;
}
/**
* Fetches raw power samples between `sinceMs` and now.
* Converts the configured field to watts based on INFLUX_FIELD_UNIT.
* Fetches raw samples for one series between `sinceMs` and now, converting
* the configured field to watts based on `fieldUnit`.
*/
export async function fetchPowerSamplesSince(
async function fetchSeriesSince(
queryApi: QueryApi,
env: Env,
config: SeriesConfig,
sinceMs: number,
): Promise<PowerSample[]> {
const sinceIso = new Date(sinceMs).toISOString();
const domainFilter = config.domain
? `|> filter(fn: (r) => r["domain"] == "${config.domain}")\n `
: "";
const entityFilter = config.entityId
? `|> filter(fn: (r) => r["entity_id"] == "${config.entityId}")\n `
: "";
const flux = `
from(bucket: "${env.INFLUX_BUCKET}")
from(bucket: "${config.bucket}")
|> range(start: ${sinceIso})
|> filter(fn: (r) => r["_measurement"] == "${env.INFLUX_FIELD_UNIT}")
|> filter(fn: (r) => r["_field"] == "${env.INFLUX_FIELD}")
|> filter(fn: (r) => r["domain"] == "${env.INFLUX_DOMAIN}")
|> filter(fn: (r) => r["entity_id"] == "${env.INFLUX_ENTITY_ID}")
|> sort(columns: ["_time"])
|> filter(fn: (r) => r["_measurement"] == "${config.fieldUnit}")
|> filter(fn: (r) => r["_field"] == "${config.field}")
${domainFilter}${entityFilter}|> sort(columns: ["_time"])
`;
const unitMultiplier = env.INFLUX_FIELD_UNIT === "kW" ? 1000 : 1;
const unitMultiplier = config.fieldUnit === "kW" ? 1000 : 1;
const samples: PowerSample[] = [];
for await (const { values, tableMeta } of queryApi.iterateRows(flux)) {
@@ -36,6 +49,29 @@ export async function fetchPowerSamplesSince(
return samples;
}
function housePowerConfig(env: Env): SeriesConfig {
return {
bucket: env.INFLUX_BUCKET,
measurement: env.INFLUX_MEASUREMENT,
field: env.INFLUX_FIELD,
fieldUnit: env.INFLUX_FIELD_UNIT,
domain: env.INFLUX_DOMAIN,
entityId: env.INFLUX_ENTITY_ID,
};
}
/**
* Fetches raw power samples between `sinceMs` and now.
* Converts the configured field to watts based on INFLUX_FIELD_UNIT.
*/
export async function fetchPowerSamplesSince(
queryApi: QueryApi,
env: Env,
sinceMs: number,
): Promise<PowerSample[]> {
return fetchSeriesSince(queryApi, housePowerConfig(env), sinceMs);
}
/** Fetches the single most recent power sample, if any exists within the lookback window. */
export async function fetchLatestPowerSample(
queryApi: QueryApi,
@@ -49,3 +85,26 @@ export async function fetchLatestPowerSample(
);
return samples.length > 0 ? samples[samples.length - 1] : null;
}
/**
* Fetches the most recent solar production sample from InfluxDB, if any
* exists within the lookback window. Returns null when no solar production
* series is configured (SOLAR_INFLUX_ENTITY_ID unset).
*/
export async function fetchLatestSolarProductionSample(
queryApi: QueryApi,
env: Env,
lookbackMs = 60_000,
): Promise<PowerSample | null> {
if (!env.SOLAR_INFLUX_ENTITY_ID) return null;
const config: SeriesConfig = {
bucket: env.INFLUX_BUCKET,
measurement: env.SOLAR_INFLUX_MEASUREMENT,
field: env.SOLAR_INFLUX_FIELD,
fieldUnit: env.SOLAR_INFLUX_FIELD_UNIT,
domain: env.SOLAR_INFLUX_DOMAIN,
entityId: env.SOLAR_INFLUX_ENTITY_ID,
};
const samples = await fetchSeriesSince(queryApi, config, Date.now() - lookbackMs);
return samples.length > 0 ? samples[samples.length - 1] : null;
}