fix: use correct Pulse API endpoints (/all-devices, data-range)
This commit is contained in:
parent
893244169d
commit
fb5dba5019
1 changed files with 101 additions and 44 deletions
|
|
@ -21,8 +21,8 @@ export interface PulseReading {
|
|||
humidity: number; // %
|
||||
vpd: number; // kPa
|
||||
dewpoint: number; // Fahrenheit
|
||||
light?: number; // PPFD (for Pro devices)
|
||||
co2?: number; // ppm (for Pro devices)
|
||||
light?: number; // lux
|
||||
co2?: number; // ppm
|
||||
timestamp: Date;
|
||||
}
|
||||
|
||||
|
|
@ -49,41 +49,73 @@ export class PulseService {
|
|||
return res.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all devices with their latest readings
|
||||
* Uses /all-devices which returns deviceViewDtos with mostRecentDataPoint
|
||||
*/
|
||||
async getAllDevicesWithReadings(): Promise<{ devices: PulseDevice[]; readings: PulseReading[] }> {
|
||||
const data = await this.fetch('/all-devices');
|
||||
|
||||
const devices: PulseDevice[] = [];
|
||||
const readings: PulseReading[] = [];
|
||||
|
||||
// Process device view DTOs
|
||||
for (const d of (data.deviceViewDtos || [])) {
|
||||
const deviceId = String(d.id || d.deviceId);
|
||||
const deviceName = d.name || 'Unknown';
|
||||
|
||||
devices.push({
|
||||
id: deviceId,
|
||||
name: deviceName,
|
||||
type: this.getDeviceType(d.deviceType),
|
||||
isOnline: d.mostRecentDataPoint?.pluggedIn ?? true,
|
||||
});
|
||||
|
||||
if (d.mostRecentDataPoint) {
|
||||
const dp = d.mostRecentDataPoint;
|
||||
readings.push({
|
||||
deviceId,
|
||||
deviceName,
|
||||
temperature: dp.temperatureF ?? 0,
|
||||
humidity: dp.humidityRh ?? 0,
|
||||
vpd: dp.vpd ?? 0,
|
||||
dewpoint: dp.dpF ?? this.calculateDewpoint(dp.temperatureF, dp.humidityRh),
|
||||
light: dp.lightLux || undefined,
|
||||
co2: dp.co2 || undefined,
|
||||
timestamp: new Date(dp.createdAt || Date.now()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Process universal sensor views if present
|
||||
for (const s of (data.universalSensorViews || [])) {
|
||||
const deviceId = String(s.id || s.deviceId);
|
||||
const deviceName = s.name || 'Unknown Sensor';
|
||||
|
||||
devices.push({
|
||||
id: deviceId,
|
||||
name: deviceName,
|
||||
type: 'universal',
|
||||
isOnline: true,
|
||||
});
|
||||
}
|
||||
|
||||
return { devices, readings };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all devices for this grow
|
||||
*/
|
||||
async getDevices(): Promise<PulseDevice[]> {
|
||||
const data = await this.fetch('/devices');
|
||||
return (data.devices || data || []).map((d: any) => ({
|
||||
id: d.id || d.deviceId,
|
||||
name: d.name || d.deviceName || 'Unknown',
|
||||
type: d.type || 'pulse',
|
||||
isOnline: d.isOnline ?? d.online ?? true,
|
||||
}));
|
||||
const { devices } = await this.getAllDevicesWithReadings();
|
||||
return devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current readings for all devices
|
||||
*/
|
||||
async getCurrentReadings(): Promise<PulseReading[]> {
|
||||
const devices = await this.getDevices();
|
||||
const readings: PulseReading[] = [];
|
||||
|
||||
for (const device of devices) {
|
||||
try {
|
||||
const reading = await this.getDeviceReading(device.id);
|
||||
if (reading) {
|
||||
readings.push({
|
||||
deviceId: device.id,
|
||||
deviceName: device.name,
|
||||
...reading,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to get reading for ${device.name}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
const { readings } = await this.getAllDevicesWithReadings();
|
||||
return readings;
|
||||
}
|
||||
|
||||
|
|
@ -92,16 +124,16 @@ export class PulseService {
|
|||
*/
|
||||
async getDeviceReading(deviceId: string): Promise<Omit<PulseReading, 'deviceId' | 'deviceName'> | null> {
|
||||
try {
|
||||
const data = await this.fetch(`/devices/${deviceId}/sensors/current`);
|
||||
const data = await this.fetch(`/devices/${deviceId}/recent-data`);
|
||||
|
||||
return {
|
||||
temperature: data.temperature?.value ?? data.temp ?? 0,
|
||||
humidity: data.humidity?.value ?? data.rh ?? 0,
|
||||
vpd: data.vpd?.value ?? data.vpd ?? 0,
|
||||
dewpoint: data.dewpoint?.value ?? data.dew ?? 0,
|
||||
light: data.ppfd?.value ?? data.light,
|
||||
co2: data.co2?.value ?? data.co2,
|
||||
timestamp: new Date(data.timestamp || Date.now()),
|
||||
temperature: data.temperatureF ?? 0,
|
||||
humidity: data.humidityRh ?? 0,
|
||||
vpd: data.vpd ?? 0,
|
||||
dewpoint: data.dpF ?? this.calculateDewpoint(data.temperatureF, data.humidityRh),
|
||||
light: data.lightLux || undefined,
|
||||
co2: data.co2 || undefined,
|
||||
timestamp: new Date(data.createdAt || Date.now()),
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
|
|
@ -113,18 +145,18 @@ export class PulseService {
|
|||
*/
|
||||
async getHistory(deviceId: string, hours: number = 24): Promise<PulseReading[]> {
|
||||
const start = new Date(Date.now() - hours * 60 * 60 * 1000).toISOString();
|
||||
const data = await this.fetch(`/devices/${deviceId}/sensors/data?start=${start}`);
|
||||
const data = await this.fetch(`/devices/${deviceId}/data-range?start=${start}`);
|
||||
|
||||
return (data.readings || data || []).map((r: any) => ({
|
||||
return (data || []).map((r: any) => ({
|
||||
deviceId,
|
||||
deviceName: '',
|
||||
temperature: r.temperature ?? r.temp ?? 0,
|
||||
humidity: r.humidity ?? r.rh ?? 0,
|
||||
temperature: r.temperatureF ?? 0,
|
||||
humidity: r.humidityRh ?? 0,
|
||||
vpd: r.vpd ?? 0,
|
||||
dewpoint: r.dewpoint ?? r.dew ?? 0,
|
||||
light: r.ppfd ?? r.light,
|
||||
co2: r.co2,
|
||||
timestamp: new Date(r.timestamp),
|
||||
dewpoint: r.dpF ?? this.calculateDewpoint(r.temperatureF, r.humidityRh),
|
||||
light: r.lightLux || undefined,
|
||||
co2: r.co2 || undefined,
|
||||
timestamp: new Date(r.createdAt),
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -133,12 +165,37 @@ export class PulseService {
|
|||
*/
|
||||
async testConnection(): Promise<{ success: boolean; deviceCount: number; error?: string }> {
|
||||
try {
|
||||
const devices = await this.getDevices();
|
||||
const { devices } = await this.getAllDevicesWithReadings();
|
||||
return { success: true, deviceCount: devices.length };
|
||||
} catch (error: any) {
|
||||
return { success: false, deviceCount: 0, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map device type number to string
|
||||
*/
|
||||
private getDeviceType(type: number): string {
|
||||
const types: Record<number, string> = {
|
||||
0: 'Pulse One',
|
||||
1: 'Pulse Pro',
|
||||
2: 'Pulse Hub',
|
||||
};
|
||||
return types[type] || 'Pulse';
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate dewpoint from temperature and humidity
|
||||
*/
|
||||
private calculateDewpoint(tempF: number, humidity: number): number {
|
||||
if (!tempF || !humidity) return 0;
|
||||
const tempC = (tempF - 32) * 5 / 9;
|
||||
const a = 17.27;
|
||||
const b = 237.7;
|
||||
const alpha = ((a * tempC) / (b + tempC)) + Math.log(humidity / 100);
|
||||
const dewpointC = (b * alpha) / (a - alpha);
|
||||
return (dewpointC * 9 / 5) + 32;
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton instance (initialized with API key from env)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue