|
|
|
@ -1035,116 +1035,302 @@ exports.mastrerList = async (req, reply) => {
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// exports.getMasterSlaveSummary = async (req, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { customerId } = req.params;
|
|
|
|
|
|
|
|
|
|
// if (!customerId) {
|
|
|
|
|
// return reply.status(400).send({ message: "Missing customerId" });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const allDevices = await Insensors.find({ customerId });
|
|
|
|
|
|
|
|
|
|
// const masters = allDevices.filter(device => device.type === 'master');
|
|
|
|
|
// const slaves = allDevices.filter(device => device.type === 'slave');
|
|
|
|
|
|
|
|
|
|
// const enrichDeviceWithTimestamp = async (device) => {
|
|
|
|
|
// const hardwareId = device.hardwareId?.trim();
|
|
|
|
|
// if (!hardwareId) return device.toObject();
|
|
|
|
|
|
|
|
|
|
// const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
|
|
|
|
|
// const enriched = device.toObject();
|
|
|
|
|
|
|
|
|
|
// if (latestData?.date) {
|
|
|
|
|
// const indiaTime = moment.tz(latestData.date, "Asia/Kolkata");
|
|
|
|
|
// const date = indiaTime.format("DD-MM-YYYY");
|
|
|
|
|
// const time = indiaTime.format("HH:mm:ss");
|
|
|
|
|
// const now = moment.tz("Asia/Kolkata");
|
|
|
|
|
// const diffInMinutes = now.diff(indiaTime, "minutes");
|
|
|
|
|
// const isGSMConnected = diffInMinutes <= 1;
|
|
|
|
|
// const gsmStatus = isGSMConnected ? "connected" : "disconnected";
|
|
|
|
|
|
|
|
|
|
// if (device.type === 'master') {
|
|
|
|
|
// enriched.connected_gsm_date = date;
|
|
|
|
|
// enriched.connected_gsm_time = time;
|
|
|
|
|
// enriched.gsm_connected_status = gsmStatus;
|
|
|
|
|
// enriched.gsm_last_check_time = indiaTime.format("YYYY-MM-DD HH:mm:ss");
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (latestData?.tanks && Array.isArray(latestData.tanks)) {
|
|
|
|
|
// const enrichedTanks = latestData.tanks.map(tank => {
|
|
|
|
|
// const tankMoment = moment.tz(tank.date, "Asia/Kolkata");
|
|
|
|
|
// const tankDiff = moment.tz("Asia/Kolkata").diff(tankMoment, "minutes");
|
|
|
|
|
// const loraStatus = tankDiff <= 1 ? "connected" : "disconnected";
|
|
|
|
|
// return {
|
|
|
|
|
// ...tank,
|
|
|
|
|
// connected_status: loraStatus
|
|
|
|
|
// };
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// enriched.tanks = enrichedTanks;
|
|
|
|
|
|
|
|
|
|
// if (device.type === 'slave') {
|
|
|
|
|
// const connectedTank = enrichedTanks.find(tank => tank.tankhardwareId === device.hardwareId);
|
|
|
|
|
// enriched.lora_connected_status = connectedTank ? connectedTank.connected_status : "disconnected";
|
|
|
|
|
// enriched.connected_lora_date = connectedTank ? moment(connectedTank.date).tz("Asia/Kolkata").format("DD-MM-YYYY") : null;
|
|
|
|
|
// enriched.connected_lora_time = connectedTank ? connectedTank.time : null;
|
|
|
|
|
// enriched.lora_last_check_time = connectedTank ? moment(connectedTank.date).tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss") : null;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (device.type === 'slave') {
|
|
|
|
|
// delete enriched.connected_gsm_date;
|
|
|
|
|
// delete enriched.connected_gsm_time;
|
|
|
|
|
// delete enriched.gsm_connected_status;
|
|
|
|
|
// delete enriched.gsm_last_check_time;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (device.type === 'master') {
|
|
|
|
|
// delete enriched.connected_lora_date;
|
|
|
|
|
// delete enriched.connected_lora_time;
|
|
|
|
|
// delete enriched.lora_connected_status;
|
|
|
|
|
// delete enriched.lora_last_check_time;
|
|
|
|
|
// delete enriched.tanks; // ✅ Remove tanks for master
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// return enriched;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const enrichedMasters = await Promise.all(masters.map(enrichDeviceWithTimestamp));
|
|
|
|
|
// const enrichedSlaves = await Promise.all(slaves.map(enrichDeviceWithTimestamp));
|
|
|
|
|
|
|
|
|
|
// const masterSummary = enrichedMasters.map(master => {
|
|
|
|
|
// const connectedSlaves = enrichedSlaves.filter(slave => slave.connected_to === master.connected_to);
|
|
|
|
|
// return {
|
|
|
|
|
// ...master,
|
|
|
|
|
// connected_slave_count: connectedSlaves.length,
|
|
|
|
|
// connected_slaves: connectedSlaves
|
|
|
|
|
// };
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// return reply.send({
|
|
|
|
|
// status_code: 200,
|
|
|
|
|
// message: "Success",
|
|
|
|
|
// master_count: enrichedMasters.length,
|
|
|
|
|
// slave_count: enrichedSlaves.length,
|
|
|
|
|
// data: masterSummary
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// console.error("Error in getMasterSlaveSummary:", err);
|
|
|
|
|
// return reply.status(500).send({
|
|
|
|
|
// status_code: 500,
|
|
|
|
|
// message: "Internal Server Error"
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// exports.getMasterSlaveSummary = async (req, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { customerId } = req.params;
|
|
|
|
|
|
|
|
|
|
// if (!customerId) {
|
|
|
|
|
// return reply.status(400).send({ message: "Missing customerId" });
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const allDevices = await Insensors.find({ customerId });
|
|
|
|
|
// const masters = allDevices.filter(d => d.type === 'master');
|
|
|
|
|
// const slaves = allDevices.filter(d => d.type === 'slave');
|
|
|
|
|
|
|
|
|
|
// const enrichDevice = async (device) => {
|
|
|
|
|
// const enriched = device.toObject();
|
|
|
|
|
// const hardwareId = device.hardwareId?.trim();
|
|
|
|
|
|
|
|
|
|
// if (!hardwareId) return enriched;
|
|
|
|
|
|
|
|
|
|
// // Fetch latest IotData blindly for this device
|
|
|
|
|
// const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
|
|
|
|
|
|
|
|
|
|
// if (latestData?.date) {
|
|
|
|
|
// const indiaTime = moment.tz(latestData.date, "Asia/Kolkata");
|
|
|
|
|
// const now = moment.tz("Asia/Kolkata");
|
|
|
|
|
// const diffMins = now.diff(indiaTime, "minutes");
|
|
|
|
|
// const isConnected = diffMins <= 1;
|
|
|
|
|
|
|
|
|
|
// enriched.connected_gsm_date = indiaTime.format("DD-MM-YYYY");
|
|
|
|
|
// enriched.connected_gsm_time = indiaTime.format("HH:mm:ss");
|
|
|
|
|
// enriched.gsm_connected_status = isConnected ? "connected" : "disconnected";
|
|
|
|
|
// enriched.gsm_last_check_time = indiaTime.format("YYYY-MM-DD HH:mm:ss");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Only apply LoRa logic for slaves
|
|
|
|
|
// if (device.type === 'slave' && latestData?.tanks?.length) {
|
|
|
|
|
// const matchingTank = latestData.tanks.find(
|
|
|
|
|
// tank => tank.tankhardwareId?.trim() === hardwareId
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// if (matchingTank) {
|
|
|
|
|
// const loraTime = moment.tz(matchingTank.date, "Asia/Kolkata");
|
|
|
|
|
// const loraDiff = moment.tz("Asia/Kolkata").diff(loraTime, "minutes");
|
|
|
|
|
// const isLoraConnected = loraDiff <= 1;
|
|
|
|
|
|
|
|
|
|
// enriched.connected_lora_date = loraTime.format("DD-MM-YYYY");
|
|
|
|
|
// enriched.connected_lora_time = matchingTank.time;
|
|
|
|
|
// enriched.lora_connected_status = isLoraConnected ? "connected" : "disconnected";
|
|
|
|
|
// enriched.lora_last_check_time = loraTime.format("YYYY-MM-DD HH:mm:ss");
|
|
|
|
|
// } else {
|
|
|
|
|
// enriched.connected_lora_date = null;
|
|
|
|
|
// enriched.connected_lora_time = null;
|
|
|
|
|
// enriched.lora_connected_status = "disconnected";
|
|
|
|
|
// enriched.lora_last_check_time = null;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Remove irrelevant fields
|
|
|
|
|
// if (device.type === 'slave') {
|
|
|
|
|
// delete enriched.tanks;
|
|
|
|
|
// }
|
|
|
|
|
// if (device.type === 'master') {
|
|
|
|
|
// delete enriched.connected_lora_date;
|
|
|
|
|
// delete enriched.connected_lora_time;
|
|
|
|
|
// delete enriched.lora_connected_status;
|
|
|
|
|
// delete enriched.lora_last_check_time;
|
|
|
|
|
// delete enriched.tanks;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// return enriched;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const enrichedMasters = await Promise.all(masters.map(enrichDevice));
|
|
|
|
|
// const enrichedSlaves = await Promise.all(slaves.map(enrichDevice));
|
|
|
|
|
|
|
|
|
|
// const masterSummary = enrichedMasters.map(master => {
|
|
|
|
|
// const connectedSlaves = enrichedSlaves.filter(
|
|
|
|
|
// slave => slave.connected_to === master.connected_to
|
|
|
|
|
// );
|
|
|
|
|
// return {
|
|
|
|
|
// ...master,
|
|
|
|
|
// connected_slave_count: connectedSlaves.length,
|
|
|
|
|
// connected_slaves: connectedSlaves
|
|
|
|
|
// };
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// return reply.send({
|
|
|
|
|
// status_code: 200,
|
|
|
|
|
// message: "Success",
|
|
|
|
|
// master_count: enrichedMasters.length,
|
|
|
|
|
// slave_count: enrichedSlaves.length,
|
|
|
|
|
// data: masterSummary
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// console.error("Error in getMasterSlaveSummary:", err);
|
|
|
|
|
// return reply.status(500).send({
|
|
|
|
|
// status_code: 500,
|
|
|
|
|
// message: "Internal Server Error"
|
|
|
|
|
// });
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
exports.getMasterSlaveSummary = async (req, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { customerId } = req.params;
|
|
|
|
|
|
|
|
|
|
if (!customerId) {
|
|
|
|
|
return reply.status(400).send({ message: "Missing customerId" });
|
|
|
|
|
return reply.status(400).send({ error: 'customerId is required' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const allDevices = await Insensors.find({ customerId });
|
|
|
|
|
// Fetch all devices for the customer
|
|
|
|
|
const allDevices = await Insensors.find({ customerId }).lean();
|
|
|
|
|
|
|
|
|
|
const masters = allDevices.filter(device => device.type === 'master');
|
|
|
|
|
const slaves = allDevices.filter(device => device.type === 'slave');
|
|
|
|
|
// Group devices
|
|
|
|
|
const masters = allDevices.filter(dev => dev.type === 'master');
|
|
|
|
|
const slaves = allDevices.filter(dev => dev.type === 'slave');
|
|
|
|
|
|
|
|
|
|
const enrichDeviceWithTimestamp = async (device) => {
|
|
|
|
|
const hardwareId = device.hardwareId?.trim();
|
|
|
|
|
if (!hardwareId) return device.toObject();
|
|
|
|
|
// Create a map of slaves by connected_to hardwareId
|
|
|
|
|
const slaveMap = {};
|
|
|
|
|
for (const slave of slaves) {
|
|
|
|
|
const masterId = slave.connected_to;
|
|
|
|
|
if (!slaveMap[masterId]) {
|
|
|
|
|
slaveMap[masterId] = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
|
|
|
|
|
const enriched = device.toObject();
|
|
|
|
|
const loraTime = slave.connected_lora_time || null;
|
|
|
|
|
const loraDate = slave.connected_lora_date || null;
|
|
|
|
|
|
|
|
|
|
if (latestData?.date) {
|
|
|
|
|
const indiaTime = moment.tz(latestData.date, "Asia/Kolkata");
|
|
|
|
|
const date = indiaTime.format("DD-MM-YYYY");
|
|
|
|
|
const time = indiaTime.format("HH:mm:ss");
|
|
|
|
|
const now = moment.tz("Asia/Kolkata");
|
|
|
|
|
const diffInMinutes = now.diff(indiaTime, "minutes");
|
|
|
|
|
const isGSMConnected = diffInMinutes <= 1;
|
|
|
|
|
const gsmStatus = isGSMConnected ? "connected" : "disconnected";
|
|
|
|
|
slaveMap[masterId].push({
|
|
|
|
|
hardwareId: slave.hardwareId,
|
|
|
|
|
tankName: slave.tankName || null,
|
|
|
|
|
location: slave.tankLocation || null,
|
|
|
|
|
connected_status: slave.connected_status || 'disconnected',
|
|
|
|
|
connected_lora_time: loraTime,
|
|
|
|
|
connected_lora_date: loraDate
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device.type === 'master') {
|
|
|
|
|
enriched.connected_gsm_date = date;
|
|
|
|
|
enriched.connected_gsm_time = time;
|
|
|
|
|
enriched.gsm_connected_status = gsmStatus;
|
|
|
|
|
enriched.gsm_last_check_time = indiaTime.format("YYYY-MM-DD HH:mm:ss");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const response = [];
|
|
|
|
|
|
|
|
|
|
if (latestData?.tanks && Array.isArray(latestData.tanks)) {
|
|
|
|
|
const enrichedTanks = latestData.tanks.map(tank => {
|
|
|
|
|
const tankMoment = moment.tz(tank.date, "Asia/Kolkata");
|
|
|
|
|
const tankDiff = moment.tz("Asia/Kolkata").diff(tankMoment, "minutes");
|
|
|
|
|
const loraStatus = tankDiff <= 1 ? "connected" : "disconnected";
|
|
|
|
|
return {
|
|
|
|
|
...tank,
|
|
|
|
|
connected_status: loraStatus
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
for (const master of masters) {
|
|
|
|
|
// Fetch latest IoT data for this master
|
|
|
|
|
const latestData = await IotData.findOne({ hardwareId: master.hardwareId })
|
|
|
|
|
.sort({ date: -1 })
|
|
|
|
|
.lean();
|
|
|
|
|
|
|
|
|
|
enriched.tanks = enrichedTanks;
|
|
|
|
|
const enriched = {
|
|
|
|
|
...master,
|
|
|
|
|
connected_status: master.connected_status || 'disconnected',
|
|
|
|
|
connected_slave_count: slaveMap[master.hardwareId]?.length || 0,
|
|
|
|
|
connected_slaves: slaveMap[master.hardwareId] || []
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (device.type === 'slave') {
|
|
|
|
|
const connectedTank = enrichedTanks.find(tank => tank.tankhardwareId === device.hardwareId);
|
|
|
|
|
enriched.lora_connected_status = connectedTank ? connectedTank.connected_status : "disconnected";
|
|
|
|
|
enriched.connected_lora_date = connectedTank ? moment(connectedTank.date).tz("Asia/Kolkata").format("DD-MM-YYYY") : null;
|
|
|
|
|
enriched.connected_lora_time = connectedTank ? connectedTank.time : null;
|
|
|
|
|
enriched.lora_last_check_time = connectedTank ? moment(connectedTank.date).tz("Asia/Kolkata").format("YYYY-MM-DD HH:mm:ss") : null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Use saved GSM fields from Insensors
|
|
|
|
|
if (master.gsm_last_check_time) {
|
|
|
|
|
enriched.gsm_last_check_time = master.gsm_last_check_time;
|
|
|
|
|
|
|
|
|
|
if (device.type === 'slave') {
|
|
|
|
|
delete enriched.connected_gsm_date;
|
|
|
|
|
delete enriched.connected_gsm_time;
|
|
|
|
|
delete enriched.gsm_connected_status;
|
|
|
|
|
delete enriched.gsm_last_check_time;
|
|
|
|
|
const indiaTime = moment.tz(master.gsm_last_check_time, 'Asia/Kolkata');
|
|
|
|
|
enriched.connected_gsm_date = indiaTime.format('DD-MM-YYYY');
|
|
|
|
|
enriched.connected_gsm_time = indiaTime.format('HH:mm:ss');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (device.type === 'master') {
|
|
|
|
|
delete enriched.connected_lora_date;
|
|
|
|
|
delete enriched.connected_lora_time;
|
|
|
|
|
delete enriched.lora_connected_status;
|
|
|
|
|
delete enriched.lora_last_check_time;
|
|
|
|
|
delete enriched.tanks; // ✅ Remove tanks for master
|
|
|
|
|
// If LoRa timestamps are available from master (some masters act like slaves too)
|
|
|
|
|
if (master.connected_lora_date && master.connected_lora_time) {
|
|
|
|
|
enriched.connected_lora_date = master.connected_lora_date;
|
|
|
|
|
enriched.connected_lora_time = master.connected_lora_time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return enriched;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const enrichedMasters = await Promise.all(masters.map(enrichDeviceWithTimestamp));
|
|
|
|
|
const enrichedSlaves = await Promise.all(slaves.map(enrichDeviceWithTimestamp));
|
|
|
|
|
|
|
|
|
|
const masterSummary = enrichedMasters.map(master => {
|
|
|
|
|
const connectedSlaves = enrichedSlaves.filter(slave => slave.connected_to === master.connected_to);
|
|
|
|
|
return {
|
|
|
|
|
...master,
|
|
|
|
|
connected_slave_count: connectedSlaves.length,
|
|
|
|
|
connected_slaves: connectedSlaves
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
response.push(enriched);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return reply.send({
|
|
|
|
|
status_code: 200,
|
|
|
|
|
message: "Success",
|
|
|
|
|
master_count: enrichedMasters.length,
|
|
|
|
|
slave_count: enrichedSlaves.length,
|
|
|
|
|
data: masterSummary
|
|
|
|
|
message: 'Master-slave summary retrieved successfully',
|
|
|
|
|
data: response
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("Error in getMasterSlaveSummary:", err);
|
|
|
|
|
return reply.status(500).send({
|
|
|
|
|
status_code: 500,
|
|
|
|
|
message: "Internal Server Error"
|
|
|
|
|
});
|
|
|
|
|
console.error('Error in getMasterSlaveSummary:', err);
|
|
|
|
|
return reply.status(500).send({ error: 'Internal Server Error' });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// exports.getIotDataByCustomer = async (req, reply) => {
|
|
|
|
|
// try {
|
|
|
|
|
// const { customerId } = req.params;
|
|
|
|
|