Enhance AI Insight with new state management and PDF export functionality. Added selectedArea state to App for better context in reports. Introduced new markdown files for documentation on AI Insight improvements and setup instructions. Updated package dependencies and fixed TypeScript errors for improved stability.
CI / lint-and-test (push) Canceled after 0s

This commit is contained in:
Alberto-Audrix committed 2026-08-11 09:19:06 +07:00
1 parent a8b49374f1
commit 2a627a2c3f
84 files changed
+8415 -2692

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
/**
* Environment standards from the CP 707 book, for client-side charting.
*
* Mirrors `TEMPERATURE_STANDARD` and `AIR_QUALITY_STANDARD` in
* `backend/services/cp707Knowledge.js` — the backend copy stays authoritative
* for anything sent to the model; this one exists only so the IoT panel can
* draw a comparison without a round trip. Keep the two in sync when the book
* edition changes.
*/
/** Target suhu pemeliharaan per umur (buku CP 707). */
const TEMPERATURE_STANDARD = [
{ from: 1, to: 2, temp_C: 32 },
{ from: 3, to: 4, temp_C: 31 },
{ from: 5, to: 7, temp_C: 30 },
{ from: 8, to: 14, temp_C: 29 },
{ from: 15, to: 21, temp_C: 28 },
{ from: 22, to: 28, temp_C: 26 },
{ from: 29, to: 35, temp_C: 23 },
{ from: 36, to: 99, temp_C: 22 },
];
/** Kelembapan ideal sama untuk semua umur menurut tabel buku: 50–70 %. */
export const HUMIDITY_RANGE_PCT = { min: 50, max: 70 };
/** Standar kualitas udara (Lampiran 3). */
export const AIR_QUALITY = {
/** Amonia: ideal <10 ppm, batas kritis >25 ppm. */
ammoniaSafe_ppm: 10,
ammoniaCritical_ppm: 25,
/** CO2: ideal <3000 ppm, kritis >3500 ppm. */
co2Ideal_ppm: 3000,
};
/**
* Suhu target untuk umur tertentu, atau null bila umurnya tidak masuk akal.
* Umur di luar tabel jatuh ke baris terakhir (36+ hari), sesuai isi buku.
*/
export const getTempStandardByDay = (dayAge: number | null | undefined): number | null => {
if (typeof dayAge !== 'number' || !Number.isFinite(dayAge) || dayAge <= 0) return null;
const row = TEMPERATURE_STANDARD.find((r) => dayAge >= r.from && dayAge <= r.to);
return row ? row.temp_C : null;
};
/**
* Number out of a display-formatted reading.
*
* `computeDashboard` hands back strings like "32,1 °C" and "62,8 %" — already
* scaled from the raw sensor encoding, which is why they are the safe source —
* so the chart has to strip the unit and accept the Indonesian decimal comma.
* A plain number passes through unchanged.
*/
export const parseReading = (value: unknown): number | null => {
if (typeof value === 'number') return Number.isFinite(value) ? value : null;
if (typeof value !== 'string' || value.trim() === '') return null;
const cleaned = value
.replace(/[^\d,.-]/g, '')
.replace(/\.(?=\d{3}\b)/g, '')
.replace(',', '.');
const n = Number(cleaned);
return Number.isFinite(n) ? n : null;
};