Files
tauron-scrapper/src/tauron/index.ts

198 lines
6.2 KiB
TypeScript

import fs from 'fs';
import axios, { Axios, AxiosResponse } from "axios";
import { wrapper } from 'axios-cookiejar-support';
import { CookieJar } from 'tough-cookie';
import { FileCookieStore } from 'tough-cookie-file-store';
import { EnergyDTO, EnergyRequestDTO, Payload, PowerDTO, PowerRequestDTO, ReadingDTO, ReadingRequestDTO } from "./types";
import { TauronConfig } from '../config';
export * from './types';
const LOGIN_API = `https://logowanie.tauron-dystrybucja.pl/login`;
const BASE_URL = 'https://elicznik.tauron-dystrybucja.pl';
const ENERGY_API = '/energia/api';
const POWER_API = '/moc/api';
const READING_API = '/odczyty/api';
/**
* Utility class for Tauron API.
* @param config - configuration of service
*/
export const Tauron = class {
#http: Axios;
#config: TauronConfig;
constructor(config: TauronConfig) {
// TODO: It should be paths instead of raw credentials
this.#config = config;
this.#http = wrapper(axios.create({
baseURL: BASE_URL,
jar: new CookieJar(new FileCookieStore(config.cookiesJarPath || './cookies.json')),
headers: {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/jxl,image/webp,image/png,image/svg+xml,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br, zstd',
'Sec-GPC': '1',
'Upgrade-Insecure-Requests': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
'Priority': 'u=0, i',
},
}));
}
/**
* Performs the whole login process flow including:
* - directing to the main page
* - doing toe actual login
* - setting the measurement base point
*/
async #login() {
await this.#http.get(LOGIN_API);
await this.#http.postForm(LOGIN_API, {
username: fs.readFileSync(this.#config.usernamePath, 'utf8'),
password: fs.readFileSync(this.#config.passwordPath, 'utf8'),
service: BASE_URL
});
await this.#http.postForm('/ustaw_punkt', {
"site[client]": this.#config.point,
"page": "energy"
});
}
/**
* Generic function which performs the HTTP request.
* If the request fails, the login attempt will be performed and the function will be invoked again
* with new session cookies.
* @param callback - function which performs the request on Axios instance being passed as argument
* @returns response from callback function
*/
async query<T>(callback: (http: Axios) => Promise<AxiosResponse<T>>): Promise<AxiosResponse<T>> {
try {
return await callback(this.#http);
} catch(e) {
console.log("Session expired, login requested");
await this.#login();
return await callback(this.#http);
}
}
/**
* Utility function to handle Tauron API shape (success field) automatically.
* @param path - HTTP API path
* @param data - the HTTP payload
* @returns original response
*/
async #queryForm<T>(path: string, data: any): Promise<T> {
const response = await this.query(h => h.postForm<Payload<T>>(path, data));
if (!response.data.success) {
throw new Error(`Invalid data request (success == false): ${JSON.stringify(response.data)}`);
}
return response.data.data;
}
/**
* Returns the energy data for specific request payload.
* @param data - the payload supported by Tauron API
* @returns the energy data from Tauron API
*/
async getEnergy(data: EnergyRequestDTO): Promise<EnergyDTO> {
return this.#queryForm<EnergyDTO>(ENERGY_API, data);
}
/**
* Returns the energy data per specific day.
* @param day - measurement day
* @param type - type of measurement, can be 'consum' (regular one) or 'average'
* @returns the energy data from Tauron API
*/
async getEnergyForDay(day: string): Promise<EnergyDTO> {
return await this.getEnergy({
type: 'consum',
profile: "full time",
from: day,
to: day,
});
}
/**
* Returns the energy data per specific dates range.
* @param from - the measurement starting date
* @param to - the measurement ending date
* @param type - type of measurement, can be 'consum' (regular one) or 'average'
* @returns the energy data from Tauron API
*/
async getEnergyForRange(from: string, to: string): Promise<EnergyDTO> {
return await this.getEnergy({
type: 'consum',
from,
to,
profile: "range"
});
}
/**
* Returns the energy data per specific year.
* @param year measurement year
* @param type - type of measurement, can be 'consum' (regular one) or 'average'
* @returns the energy data from Tauron API
*/
async getEnergyForYear(year: string): Promise<EnergyDTO> {
return await this.getEnergy({
type: 'consum',
profile: "year",
from: `01.01.${year}`,
to: `31.12.${year}`,
});
}
/**
* Returns the power data for specific request payload.
* @param data - the payload supported by Tauron API
* @returns the power data from Tauron API
*/
async getPower(data: PowerRequestDTO): Promise<PowerDTO[]> {
return this.#queryForm<PowerDTO[]>(POWER_API, data);
}
/**
* Returns the power data per specific dates range.
* @param from - the measurement starting date
* @param to - the measurement ending date
* @returns the power data from Tauron API
*/
async getPowerForRange(from: string, to: string): Promise<PowerDTO[]> {
return await this.getPower({ from, to });
}
/**
* Returns the reading data for specific request payload.
* @param data - the payload supported by Tauron API
* @returns the reading data from Tauron API
*/
async getReading(data: ReadingRequestDTO): Promise<ReadingDTO[]> {
return this.#queryForm<ReadingDTO[]>(READING_API, data);
}
/**
* Returns the readings per specific dates range.
* @param from - the measurement starting date
* @param to - the measurement ending date
* @returns the readings from Tauron API
*/
async getReadingForRange(from: string, to: string): Promise<ReadingDTO[]> {
return await this.getReading({
from,
to,
type: 'energia-pobrana',
});
}
};