All files / src/core mqttHandler.ts

0% Statements 0/66
0% Branches 0/23
0% Functions 0/8
0% Lines 0/65

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174                                                                                                                                                                                                                                                                                                                                                           
import { MqttClient } from 'mqtt';
 
export class MqttMessageHandler {
  private client: MqttClient | null;
 
  constructor(client: MqttClient | null) {
    this.client = client;
  }
 
  public setClient(client: MqttClient) {
    this.client = client;
  }
  
  // Store last air-sensing data for each MAC address
  private lastAirSensingData: Record<string, {
    temperature?: number;
    humidity?: number;
    co2?: number;
    pm1_0?: number;
    pm2_5?: number;
    pm10?: number;
    timestamp?: Date;
  }> = {};
 
  // Store tag data for each MAC address
  private tagData: Record<string, {
    timestamp: Date;
    beacons: Array<{ id: number; rssi: number, floor_id: number }>;
  }> = {};
 
  public async handleMessage(topic: string, mqttMessage: string): Promise<void> {
    try {
      const value = parseFloat(mqttMessage); // Parse the payload as a number
      Iif (topic.startsWith('smartclassroom/tag/')) {
        const segments = topic.split('/');
        const macAddress = segments[2]; // Extract the MAC address (3rd segment)
 
        Iif (!macAddress) {
          console.error('[MQTT] Invalid topic format: Missing MAC address');
          return;
        }
 
        const message = JSON.parse(mqttMessage);
 
        Iif (!message.beaconData || !message.beaconData.Beacons) {
          console.error('[MQTT] Invalid message format: Missing beacon data');
          return;
        }
 
        const { Beacons } = message.beaconData;
 
        // Map Beacons to include floor_id (defaulting to 0 or another value if not provided)
        const beacons = Beacons.map((beacon: { id: number; rssi: number; floor_id: number; }) => ({
          id: beacon.id,
          rssi: beacon.rssi,
          floor_id: beacon.floor_id,
        }));
 
        // Store the tag data by MAC address
        this.tagData[macAddress] = {
          timestamp: new Date(),
          beacons: beacons,
        };
 
        console.log(`[MQTT] Logged beacon data for tag ${macAddress}`);
      }
 
      Iif (topic.startsWith('smartclassroom/air-sensing/')) {
        const segments = topic.split('/');
        let macAddress = segments[2]; // Extract the MAC address (3rd segment)
        const dataType = segments[3]; // Extract the data type (e.g., temperature, humidity, co2, etc.)
 
        Iif (!macAddress || !dataType) {
          console.error('[MQTT] Invalid topic format: Missing MAC address or data type');
          return;
        }
 
        // Normalize the MAC address (trim and convert to lowercase)
        macAddress = macAddress.trim().toLowerCase();
 
        // Initialize the data object for the MAC address if it doesn't exist
        Iif (!this.lastAirSensingData[macAddress]) {
          this.lastAirSensingData[macAddress] = {};
        }
 
        // Update the corresponding field in the lastAirSensingData object
        switch (dataType) {
          case 'temperature':
            this.lastAirSensingData[macAddress].temperature = value;
            break;
          case 'humidity':
            this.lastAirSensingData[macAddress].humidity = value;
            break;
          case 'co2':
            this.lastAirSensingData[macAddress].co2 = value;
            break;
          case 'air-quality-pm1_0':
            this.lastAirSensingData[macAddress].pm1_0 = value;
            break;
          case 'air-quality-pm2_5':
            this.lastAirSensingData[macAddress].pm2_5 = value;
            break;
          case 'air-quality-pm10':
            this.lastAirSensingData[macAddress].pm10 = value;
            break;
          default:
            console.warn(`[MQTT] Unhandled data type: ${dataType}`);
            return;
        }
      }
    } catch (err) {
      console.error('[MQTT] Failed to process message:', err);
    }
  }
 
  public getAllAirSensingData(): Record<string, {
    temperature?: number;
    humidity?: number;
    co2?: number;
    pm1_0?: number;
    pm2_5?: number;
    pm10?: number;
    timestamp?: Date; // Include timestamp for each MAC address
  }> {
    // Add a timestamp to each MAC address entry
    for (const macAddress in this.lastAirSensingData) {
      Iif (this.lastAirSensingData.hasOwnProperty(macAddress)) {
        this.lastAirSensingData[macAddress].timestamp = new Date(); // Set the current timestamp
      }
    }
 
    // Store the current data to return
    const dataToReturn = { ...this.lastAirSensingData };
 
    // Clear the lastAirSensingData after sending
    this.lastAirSensingData = {};
 
    return dataToReturn;
  }
 
  // Method to get all tag data by MAC address
  public getAllTagData(): Record<string, {
    timestamp: Date;
    beacons: Array<{ id: number; rssi: number, floor_id: number }>;
  }> {
    for (const macAddress in this.tagData) {
      Iif (this.tagData.hasOwnProperty(macAddress)) {
        this.tagData[macAddress].timestamp = new Date(); // Set the current timestamp
      }
    }
 
    // Store the current data to return
    const dataToReturn = { ...this.tagData };
 
    // Clear the lastAirSensingData after sending
    this.tagData = {};
 
    return dataToReturn;
  }
 
  public sendMessage(topic: string, message: string): void {
    if (this.client) {
      this.client.publish(topic, message, { qos: 1 }, (err) => {
        if (err) {
          console.error(`[MQTT] Publish error for topic ${topic}:`, err.message);
        } else {
          console.log(`[MQTT] Published to: ${topic}`);
        }
      });
    } else {
      console.error('[MQTT] Client not connected. Cannot publish message.');
    }
  }
}