save data to sqlite

This commit is contained in:
Evert Prants 2023-09-17 09:54:01 +03:00
parent 11e1d1b468
commit 53d7efc20a
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
6 changed files with 942 additions and 64 deletions

3
.gitignore vendored
View File

@ -1,6 +1,7 @@
# compiled output
/dist
/node_modules
*.sqlite
# Logs
logs
@ -32,4 +33,4 @@ lerna-debug.log*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/extensions.json

View File

@ -25,9 +25,12 @@
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/schedule": "^3.0.3",
"@nestjs/typeorm": "^10.0.0",
"cache-manager": "^5.2.3",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"sqlite3": "^5.1.6",
"typeorm": "^0.3.17",
"usb": "^2.10.0"
},
"devDependencies": {

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,24 @@
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CacheModule } from '@nestjs/cache-manager';
import { TypeOrmModule } from '@nestjs/typeorm';
import { join } from 'path';
import { WeatherEntity } from './entities/weather.entity';
@Module({
imports: [CacheModule.register()],
imports: [
CacheModule.register(),
TypeOrmModule.forRoot({
type: 'sqlite',
database: join(process.cwd(), 'data.sqlite'),
entities: [WeatherEntity],
synchronize: true,
}),
TypeOrmModule.forFeature([WeatherEntity]),
ScheduleModule.forRoot(),
],
controllers: [AppController],
providers: [AppService],
})

View File

@ -1,13 +1,70 @@
import { Injectable, OnApplicationShutdown } from '@nestjs/common';
import {
Injectable,
InternalServerErrorException,
Logger,
OnApplicationShutdown,
} from '@nestjs/common';
import WS1080 from './module/ws1080';
import { Repository } from 'typeorm';
import { WeatherEntity } from './entities/weather.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Cron } from '@nestjs/schedule';
@Injectable()
export class AppService implements OnApplicationShutdown {
private logger = new Logger(AppService.name);
public station?: WS1080;
constructor(
@InjectRepository(WeatherEntity)
private readonly weatherRepository: Repository<WeatherEntity>,
) {}
async getWeather() {
if (!this.station) this.station = WS1080.fromDevice();
return this.station.read();
try {
// Retrieve from USB
if (!this.station) this.station = WS1080.fromDevice();
const data = await this.station.read();
// Save weather data to database
const entity = this.weatherRepository.create({
date: new Date(),
...data,
});
await this.weatherRepository.save(entity);
entity.fresh = true;
return entity;
} catch (error) {
// USB errors likely mean we are not connected anymore
if (error.message?.includes('USB')) {
try {
this.station?.close();
} catch {}
this.station = null;
}
this.logger.error('Failed to retrieve weather data:', error.stack);
// Retrieve previous entry on error
const [previous] = await this.weatherRepository.find({
order: { date: -1 },
take: 1,
});
if (!previous) throw new InternalServerErrorException();
previous.fresh = false;
return previous;
}
}
@Cron('0 * * * *')
scheduledPulls() {
this.getWeather().catch(() => {
// do nothing
});
}
onApplicationShutdown() {

View File

@ -0,0 +1,48 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class WeatherEntity {
@PrimaryGeneratedColumn()
id: number;
@Column({ type: Date })
date: Date;
@Column({ nullable: true })
indoorHumidity: number;
@Column({ nullable: true })
outdoorHumidity: number;
@Column({ nullable: true })
indoorTemperature: number;
@Column({ nullable: true })
outdoorTemperature: number;
@Column({ nullable: true })
outdoorDewPoint: number;
@Column({ nullable: true })
windChillTemp: number;
@Column({ nullable: true })
windSpeed: number;
@Column({ nullable: true })
gustSpeed: number;
@Column({ nullable: true })
windDirection: string;
@Column({ nullable: true })
rainDiff: number;
@Column({ nullable: true })
totalRain: number;
@Column({ nullable: true })
absPressure: number;
fresh?: boolean;
}