|  |  |  | @ -839,3 +839,252 @@ exports.mastrerList = async (req, reply) => { | 
			
		
	
		
			
				
					|  |  |  |  |     return reply.status(500).send({ success: false, message: "Internal Server Error" }); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //const Insensor = mongoose.model('insensors', insensorsSchema); // if not already defined
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | // exports.getMasterSlaveSummary = async (req, reply) => {
 | 
			
		
	
		
			
				
					|  |  |  |  | //   const { customerId } = req.params;
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //   try {
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const masters = await Insensors.aggregate([
 | 
			
		
	
		
			
				
					|  |  |  |  | //       {
 | 
			
		
	
		
			
				
					|  |  |  |  | //         $match: {
 | 
			
		
	
		
			
				
					|  |  |  |  | //           customerId,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           type: "master"
 | 
			
		
	
		
			
				
					|  |  |  |  | //         }
 | 
			
		
	
		
			
				
					|  |  |  |  | //       },
 | 
			
		
	
		
			
				
					|  |  |  |  | //       {
 | 
			
		
	
		
			
				
					|  |  |  |  | //         $lookup: {
 | 
			
		
	
		
			
				
					|  |  |  |  | //           from: 'Insensors', // collection name should match MongoDB collection
 | 
			
		
	
		
			
				
					|  |  |  |  | //           let: { masterId: '$hardwareId' },
 | 
			
		
	
		
			
				
					|  |  |  |  | //           pipeline: [
 | 
			
		
	
		
			
				
					|  |  |  |  | //             {
 | 
			
		
	
		
			
				
					|  |  |  |  | //               $match: {
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 $expr: {
 | 
			
		
	
		
			
				
					|  |  |  |  | //                   $and: [
 | 
			
		
	
		
			
				
					|  |  |  |  | //                     { $eq: ['$type', 'slave'] },
 | 
			
		
	
		
			
				
					|  |  |  |  | //                     { $eq: ['$customerId', customerId] },
 | 
			
		
	
		
			
				
					|  |  |  |  | //                     { $eq: ['$connected_to', '$$masterId'] }
 | 
			
		
	
		
			
				
					|  |  |  |  | //                   ]
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 }
 | 
			
		
	
		
			
				
					|  |  |  |  | //               }
 | 
			
		
	
		
			
				
					|  |  |  |  | //             },
 | 
			
		
	
		
			
				
					|  |  |  |  | //             {
 | 
			
		
	
		
			
				
					|  |  |  |  | //               $project: {
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 _id: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 hardwareId: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 tankName: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 tankLocation: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 model: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 status: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //                 indate: 1
 | 
			
		
	
		
			
				
					|  |  |  |  | //               }
 | 
			
		
	
		
			
				
					|  |  |  |  | //             }
 | 
			
		
	
		
			
				
					|  |  |  |  | //           ],
 | 
			
		
	
		
			
				
					|  |  |  |  | //           as: 'connected_slaves'
 | 
			
		
	
		
			
				
					|  |  |  |  | //         }
 | 
			
		
	
		
			
				
					|  |  |  |  | //       },
 | 
			
		
	
		
			
				
					|  |  |  |  | //       {
 | 
			
		
	
		
			
				
					|  |  |  |  | //         $addFields: {
 | 
			
		
	
		
			
				
					|  |  |  |  | //           connected_slave_count: { $size: '$connected_slaves' }
 | 
			
		
	
		
			
				
					|  |  |  |  | //         }
 | 
			
		
	
		
			
				
					|  |  |  |  | //       },
 | 
			
		
	
		
			
				
					|  |  |  |  | //       {
 | 
			
		
	
		
			
				
					|  |  |  |  | //         $project: {
 | 
			
		
	
		
			
				
					|  |  |  |  | //           _id: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           hardwareId: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           tankName: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           tankLocation: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           model: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           status: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           indate: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           connected_slave_count: 1,
 | 
			
		
	
		
			
				
					|  |  |  |  | //           connected_slaves: 1
 | 
			
		
	
		
			
				
					|  |  |  |  | //         }
 | 
			
		
	
		
			
				
					|  |  |  |  | //       }
 | 
			
		
	
		
			
				
					|  |  |  |  | //     ]);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const totalMasters = await Insensors.countDocuments({ customerId, type: 'master' });
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const totalSlaves = await Insensors.countDocuments({ customerId, type: 'slave' });
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     reply.code(200).send({
 | 
			
		
	
		
			
				
					|  |  |  |  | //       totalMasters,
 | 
			
		
	
		
			
				
					|  |  |  |  | //       totalSlaves,
 | 
			
		
	
		
			
				
					|  |  |  |  | //       masters
 | 
			
		
	
		
			
				
					|  |  |  |  | //     });
 | 
			
		
	
		
			
				
					|  |  |  |  | //   } catch (err) {
 | 
			
		
	
		
			
				
					|  |  |  |  | //     console.error(err);
 | 
			
		
	
		
			
				
					|  |  |  |  | //     reply.code(500).send({ error: 'Server error', details: err.message });
 | 
			
		
	
		
			
				
					|  |  |  |  | //   }
 | 
			
		
	
		
			
				
					|  |  |  |  | // }
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | exports.getMasterSlaveSummary = async (req, reply) => { | 
			
		
	
		
			
				
					|  |  |  |  |   try { | 
			
		
	
		
			
				
					|  |  |  |  |     const { customerId } = req.params; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (!customerId) { | 
			
		
	
		
			
				
					|  |  |  |  |       return reply.status(400).send({ message: "Missing customerId" }); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Get all devices for customer
 | 
			
		
	
		
			
				
					|  |  |  |  |     const allDevices = await Insensors.find({ customerId }).lean(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Separate masters and slaves
 | 
			
		
	
		
			
				
					|  |  |  |  |     const masters = allDevices.filter(device => device.type === 'master'); | 
			
		
	
		
			
				
					|  |  |  |  |     const slaves = allDevices.filter(device => device.type === 'slave'); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // Map masters to their connected slaves based on `connected_to` match
 | 
			
		
	
		
			
				
					|  |  |  |  |     const enrichedMasters = masters.map(master => { | 
			
		
	
		
			
				
					|  |  |  |  |       const masterConnectionId = master.connected_to; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       const connectedSlaves = slaves.filter(slave =>  | 
			
		
	
		
			
				
					|  |  |  |  |         slave.connected_to === masterConnectionId | 
			
		
	
		
			
				
					|  |  |  |  |       ); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       return { | 
			
		
	
		
			
				
					|  |  |  |  |         ...master, | 
			
		
	
		
			
				
					|  |  |  |  |         connected_slave_count: connectedSlaves.length, | 
			
		
	
		
			
				
					|  |  |  |  |         connected_slaves: connectedSlaves | 
			
		
	
		
			
				
					|  |  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     return reply.send({ | 
			
		
	
		
			
				
					|  |  |  |  |       status_code: 200, | 
			
		
	
		
			
				
					|  |  |  |  |       message: "Success", | 
			
		
	
		
			
				
					|  |  |  |  |       master_count: masters.length, | 
			
		
	
		
			
				
					|  |  |  |  |       slave_count: slaves.length, | 
			
		
	
		
			
				
					|  |  |  |  |       data: enrichedMasters | 
			
		
	
		
			
				
					|  |  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   } catch (err) { | 
			
		
	
		
			
				
					|  |  |  |  |     console.error("Error:", err); | 
			
		
	
		
			
				
					|  |  |  |  |     return reply.status(500).send({ | 
			
		
	
		
			
				
					|  |  |  |  |       status_code: 500, | 
			
		
	
		
			
				
					|  |  |  |  |       message: "Internal Server Error" | 
			
		
	
		
			
				
					|  |  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | // exports.getIotDataByCustomer = async (req, reply) => {
 | 
			
		
	
		
			
				
					|  |  |  |  | //   try {
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const { customerId } = req.params;
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     if (!customerId) {
 | 
			
		
	
		
			
				
					|  |  |  |  | //       return reply.code(400).send({ error: "customerId is required" });
 | 
			
		
	
		
			
				
					|  |  |  |  | //     }
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     // 1. Fetch all tanks by customerId
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const tanks = await Tank.find({ customerId });
 | 
			
		
	
		
			
				
					|  |  |  |  | //     console.log("Tanks found:", tanks.length);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     if (!tanks || tanks.length === 0) {
 | 
			
		
	
		
			
				
					|  |  |  |  | //       return reply.code(404).send({ message: "No tanks found for this customer." });
 | 
			
		
	
		
			
				
					|  |  |  |  | //     }
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     // 2. Collect all motor_ids from input & output connections
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const motorIdSet = new Set();
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     for (const tank of tanks) {
 | 
			
		
	
		
			
				
					|  |  |  |  | //       const { inputConnections = [], outputConnections = [] } = tank.connections || {};
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //       inputConnections.forEach(conn => {
 | 
			
		
	
		
			
				
					|  |  |  |  | //         if (conn.motor_id) motorIdSet.add(conn.motor_id.trim());
 | 
			
		
	
		
			
				
					|  |  |  |  | //       });
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //       outputConnections.forEach(conn => {
 | 
			
		
	
		
			
				
					|  |  |  |  | //         if (conn.motor_id) motorIdSet.add(conn.motor_id.trim());
 | 
			
		
	
		
			
				
					|  |  |  |  | //       });
 | 
			
		
	
		
			
				
					|  |  |  |  | //     }
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const motorIds = Array.from(motorIdSet);
 | 
			
		
	
		
			
				
					|  |  |  |  | //     console.log("Unique motorIds collected:", motorIds);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     if (motorIds.length === 0) {
 | 
			
		
	
		
			
				
					|  |  |  |  | //       return reply.send({ status_code: 200, message: "No motors connected", data: [] });
 | 
			
		
	
		
			
				
					|  |  |  |  | //     }
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     // 3. Fetch the latest IotData for each unique hardwareId
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const latestIotDataPromises = motorIds.map(hardwareId =>
 | 
			
		
	
		
			
				
					|  |  |  |  | //       IotData.findOne({ hardwareId }).sort({ date: -1 }).lean()
 | 
			
		
	
		
			
				
					|  |  |  |  | //     );
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const iotDataResults = await Promise.all(latestIotDataPromises);
 | 
			
		
	
		
			
				
					|  |  |  |  | //     const filteredData = iotDataResults.filter(doc => doc); // remove nulls
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     console.log("Latest IotData entries found:", filteredData.length);
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //     return reply.send({
 | 
			
		
	
		
			
				
					|  |  |  |  | //       status_code: 200,
 | 
			
		
	
		
			
				
					|  |  |  |  | //       message: "Success",
 | 
			
		
	
		
			
				
					|  |  |  |  | //       data: filteredData
 | 
			
		
	
		
			
				
					|  |  |  |  | //     });
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | //   } catch (err) {
 | 
			
		
	
		
			
				
					|  |  |  |  | //     console.error("Error fetching IoT data by customerId:", err);
 | 
			
		
	
		
			
				
					|  |  |  |  | //     return reply.code(500).send({ error: "Internal Server Error" });
 | 
			
		
	
		
			
				
					|  |  |  |  | //   }
 | 
			
		
	
		
			
				
					|  |  |  |  | // };
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | exports.getIotDataByCustomer = async (req, reply) => { | 
			
		
	
		
			
				
					|  |  |  |  |   try { | 
			
		
	
		
			
				
					|  |  |  |  |     const { customerId } = req.params; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (!customerId) { | 
			
		
	
		
			
				
					|  |  |  |  |       return reply.code(400).send({ error: "customerId is required" }); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // 1. Fetch all insensors for this customer
 | 
			
		
	
		
			
				
					|  |  |  |  |     const sensors = await Insensors.find({ customerId }); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     console.log("Sensors found:", sensors.length); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (!sensors || sensors.length === 0) { | 
			
		
	
		
			
				
					|  |  |  |  |       return reply.code(404).send({ message: "No sensors found for this customer." }); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // 2. Get unique connected_to hardwareIds
 | 
			
		
	
		
			
				
					|  |  |  |  |     const hardwareIds = [ | 
			
		
	
		
			
				
					|  |  |  |  |       ...new Set( | 
			
		
	
		
			
				
					|  |  |  |  |         sensors | 
			
		
	
		
			
				
					|  |  |  |  |           .map(sensor => sensor.connected_to?.trim()) | 
			
		
	
		
			
				
					|  |  |  |  |           .filter(Boolean) | 
			
		
	
		
			
				
					|  |  |  |  |       ), | 
			
		
	
		
			
				
					|  |  |  |  |     ]; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     console.log("Collected hardwareIds:", hardwareIds); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if (hardwareIds.length === 0) { | 
			
		
	
		
			
				
					|  |  |  |  |       return reply.send({ status_code: 200, message: "No connected hardwareIds found", data: [] }); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     // 3. Fetch latest 3 records per hardwareId
 | 
			
		
	
		
			
				
					|  |  |  |  |     const latestDataPromises = hardwareIds.map(async hardwareId => { | 
			
		
	
		
			
				
					|  |  |  |  |       const records = await IotData.find({ hardwareId }) | 
			
		
	
		
			
				
					|  |  |  |  |         .sort({ date: -1 }) | 
			
		
	
		
			
				
					|  |  |  |  |         .limit(3) | 
			
		
	
		
			
				
					|  |  |  |  |         .lean(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |       return { | 
			
		
	
		
			
				
					|  |  |  |  |         hardwareId, | 
			
		
	
		
			
				
					|  |  |  |  |         records, | 
			
		
	
		
			
				
					|  |  |  |  |       }; | 
			
		
	
		
			
				
					|  |  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     const iotDataGrouped = await Promise.all(latestDataPromises); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     return reply.send({ | 
			
		
	
		
			
				
					|  |  |  |  |       status_code: 200, | 
			
		
	
		
			
				
					|  |  |  |  |       message: "Success", | 
			
		
	
		
			
				
					|  |  |  |  |       data: iotDataGrouped, | 
			
		
	
		
			
				
					|  |  |  |  |     }); | 
			
		
	
		
			
				
					|  |  |  |  |   } catch (err) { | 
			
		
	
		
			
				
					|  |  |  |  |     console.error("Error fetching IoT data by customerId:", err); | 
			
		
	
		
			
				
					|  |  |  |  |     return reply.code(500).send({ error: "Internal Server Error" }); | 
			
		
	
		
			
				
					|  |  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  |  | }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |