Weather Station / ECOWITT / DNT
1import { promises as fs } from "fs";
2import path from "path";
3
4/**
5 * The absolute path to the DNT directory where CSV files are stored.
6 */
7export const DNT_DIR = path.join(process.cwd(), "DNT");
8
9/**
10 * Lists all CSV files in the DNT directory.
11 * @returns {Promise<string[]>} A promise that resolves to an array of CSV filenames.
12 */
13export async function listDntFiles(): Promise<string[]> {
14 const items = await fs.readdir(DNT_DIR);
15 return items.filter((f) => f.toLowerCase().endsWith(".csv"));
16}
17
18/**
19 * Converts a Date object to a YYYYMM number.
20 * @param {Date} [d] - The date to convert.
21 * @returns {number | null} The date as a YYYYMM number, or null if the date is not provided.
22 * @private
23 */
24function ymOf(d?: Date): number | null {
25 if (!d) return null;
26 return d.getFullYear() * 100 + (d.getMonth() + 1);
27}
28
29/**
30 * Gets all 'allsensors' CSV files within a given date range.
31 * @param {Date} [start] - The start date of the range.
32 * @param {Date} [end] - The end date of the range.
33 * @returns {Promise<string[]>} A promise that resolves to an array of filenames.
34 */
35export async function getAllsensorsFilesInRange(start?: Date, end?: Date): Promise<string[]> {
36 const files = await listDntFiles();
37 // match case-insensitively: 202501Allsensors_A.csv / .CSV
38 const list = files
39 .filter((f) => /^\d{6}allsensors_a\.csv$/.test(f.toLowerCase()))
40 .sort();
41 const ys = ymOf(start);
42 const ye = ymOf(end);
43 if (!ys && !ye) return list;
44 return list.filter((f) => {
45 const ym = Number(f.slice(0, 6));
46 if (ys && ym < ys) return false;
47 if (ye && ym > ye) return false;
48 return true;
49 });
50}
51
52/**
53 * Gets all 'main' CSV files within a given date range.
54 * @param {Date} [start] - The start date of the range.
55 * @param {Date} [end] - The end date of the range.
56 * @returns {Promise<string[]>} A promise that resolves to an array of filenames.
57 */
58export async function getMainFilesInRange(start?: Date, end?: Date): Promise<string[]> {
59 const files = await listDntFiles();
60 // match case-insensitively: 202501A.csv / .CSV
61 const list = files
62 .filter((f) => /^\d{6}a\.csv$/.test(f.toLowerCase()))
63 .sort();
64 const ys = ymOf(start);
65 const ye = ymOf(end);
66 if (!ys && !ye) return list;
67 return list.filter((f) => {
68 const ym = Number(f.slice(0, 6));
69 if (ys && ym < ys) return false;
70 if (ye && ym > ye) return false;
71 return true;
72 });
73}
74
75/**
76 * Finds the latest file in the DNT directory that matches a regular expression.
77 * @param {RegExp} rxLower - The regular expression to match against lowercase filenames.
78 * @returns {Promise<string | null>} A promise that resolves to the filename, or null if no match is found.
79 */
80export async function latestFileMatching(rxLower: RegExp): Promise<string | null> {
81 const files = await listDntFiles();
82 const m = files.filter((f) => rxLower.test(f.toLowerCase())).sort();
83 return m.length ? m[m.length - 1] : null;
84}
85
86/**
87 * Gets the 'allsensors' filename for a specific month, or the latest one if no month is provided.
88 * @param {string} [month] - The month in YYYYMM format.
89 * @returns {Promise<string | null>} A promise that resolves to the filename, or null if not found.
90 */
91export async function getAllsensorsFilename(month?: string): Promise<string | null> {
92 const files = await listDntFiles();
93 if (month && /^\d{6}$/.test(month)) {
94 const targetLower = `${month}allsensors_a.csv`;
95 const found = files.find((f) => f.toLowerCase() === targetLower);
96 if (found) return found;
97 }
98 return latestFileMatching(/^\d{6}allsensors_a\.csv$/);
99}
100
101/**
102 * Gets the 'main' filename for a specific month, or the latest one if no month is provided.
103 * @param {string} [month] - The month in YYYYMM format.
104 * @returns {Promise<string | null>} A promise that resolves to the filename, or null if not found.
105 */
106export async function getMainFilename(month?: string): Promise<string | null> {
107 const files = await listDntFiles();
108 if (month && /^\d{6}$/.test(month)) {
109 const targetLower = `${month}a.csv`;
110 const found = files.find((f) => f.toLowerCase() === targetLower);
111 if (found) return found;
112 }
113 return latestFileMatching(/^\d{6}a\.csv$/);
114}