|
|
@ -740,6 +740,7 @@ exports.getByHardwareIdSupport = async (req, reply) => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.getByHardwareAndTankId = async (req, reply) => {
|
|
|
|
exports.getByHardwareAndTankId = async (req, reply) => {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const { hardwareId, tankhardwareId } = req.params;
|
|
|
|
const { hardwareId, tankhardwareId } = req.params;
|
|
|
@ -748,11 +749,9 @@ exports.getByHardwareAndTankId = async (req, reply) => {
|
|
|
|
return reply.status(400).send({ error: "Both hardwareId and tankhardwareId are required" });
|
|
|
|
return reply.status(400).send({ error: "Both hardwareId and tankhardwareId are required" });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log("Fetching tank data for:", { hardwareId, tankhardwareId });
|
|
|
|
console.log("📡 Fetching data for:", { hardwareId, tankhardwareId });
|
|
|
|
|
|
|
|
|
|
|
|
const latestData = await IotData.findOne({ hardwareId })
|
|
|
|
const latestData = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
|
|
|
|
.sort({ date: -1 })
|
|
|
|
|
|
|
|
.lean();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!latestData || !Array.isArray(latestData.tanks)) {
|
|
|
|
if (!latestData || !Array.isArray(latestData.tanks)) {
|
|
|
|
return reply.code(404).send({ message: "No data found for given hardwareId and tankhardwareId" });
|
|
|
|
return reply.code(404).send({ message: "No data found for given hardwareId and tankhardwareId" });
|
|
|
@ -760,8 +759,7 @@ exports.getByHardwareAndTankId = async (req, reply) => {
|
|
|
|
|
|
|
|
|
|
|
|
const now = new Date();
|
|
|
|
const now = new Date();
|
|
|
|
const dataDate = new Date(latestData.date);
|
|
|
|
const dataDate = new Date(latestData.date);
|
|
|
|
const diffInMs = now - dataDate;
|
|
|
|
const isGSMConnected = now - dataDate <= 60000;
|
|
|
|
const isGSMConnected = diffInMs <= 60000;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const matchedTank = latestData.tanks.find(tank => tank.tankhardwareId === tankhardwareId);
|
|
|
|
const matchedTank = latestData.tanks.find(tank => tank.tankhardwareId === tankhardwareId);
|
|
|
|
|
|
|
|
|
|
|
@ -772,58 +770,50 @@ exports.getByHardwareAndTankId = async (req, reply) => {
|
|
|
|
const tankHeight = parseFloat(matchedTank.tankHeight || "0");
|
|
|
|
const tankHeight = parseFloat(matchedTank.tankHeight || "0");
|
|
|
|
const isLoraConnected = isGSMConnected && tankHeight > 0;
|
|
|
|
const isLoraConnected = isGSMConnected && tankHeight > 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Format date and time from matched tank
|
|
|
|
const matchedTankDateObj = new Date(matchedTank.date);
|
|
|
|
const matchedTankDateObj = new Date(matchedTank.date);
|
|
|
|
const day = String(matchedTankDateObj.getDate()).padStart(2, '0');
|
|
|
|
const formattedDate = moment(matchedTankDateObj).tz("Asia/Kolkata").format("DD-MM-YYYY");
|
|
|
|
const month = String(matchedTankDateObj.getMonth() + 1).padStart(2, '0');
|
|
|
|
const formattedTime = matchedTank.time || moment(matchedTankDateObj).tz("Asia/Kolkata").format("HH:mm:ss");
|
|
|
|
const year = matchedTankDateObj.getFullYear();
|
|
|
|
|
|
|
|
const formattedDate = `${day}-${month}-${year}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
matchedTank.date = formattedDate;
|
|
|
|
matchedTank.date = formattedDate;
|
|
|
|
|
|
|
|
matchedTank.time = formattedTime;
|
|
|
|
|
|
|
|
|
|
|
|
const updateFields = {
|
|
|
|
const updateFields = {
|
|
|
|
connected_status: isLoraConnected ? "connected" : "disconnected"
|
|
|
|
connected_status: isLoraConnected ? "connected" : "disconnected",
|
|
|
|
|
|
|
|
connected_lora_date: formattedDate,
|
|
|
|
|
|
|
|
connected_lora_time: formattedTime,
|
|
|
|
|
|
|
|
lora_last_check_time: moment().tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss")
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let connected_lora_date = null;
|
|
|
|
// Check if Insensors document exists before updating
|
|
|
|
let connected_lora_time = null;
|
|
|
|
const sensorDoc = await Insensors.findOne({ connected_to: hardwareId, hardwareId: tankhardwareId });
|
|
|
|
let lora_last_check_time = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isLoraConnected) {
|
|
|
|
if (!sensorDoc) {
|
|
|
|
connected_lora_date = formattedDate;
|
|
|
|
console.warn("⚠️ No Insensors doc found with:", { connected_to: hardwareId, hardwareId: tankhardwareId });
|
|
|
|
connected_lora_time = matchedTank.time || matchedTankDateObj.toTimeString().split(" ")[0];
|
|
|
|
} else {
|
|
|
|
updateFields.connected_lora_date = connected_lora_date;
|
|
|
|
const updated = await Insensors.findByIdAndUpdate(sensorDoc._id, { $set: updateFields }, { new: true });
|
|
|
|
updateFields.connected_lora_time = connected_lora_time;
|
|
|
|
console.log("✅ Insensors updated:", updated._id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Format LoRa last check time in "YYYY-MM-DD HH:mm:ss"
|
|
|
|
|
|
|
|
lora_last_check_time = moment.tz("Asia/Kolkata").format("DD-MM-YYYY HH:mm:ss");
|
|
|
|
|
|
|
|
updateFields.lora_last_check_time = lora_last_check_time;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await Insensors.findOneAndUpdate(
|
|
|
|
|
|
|
|
{ connected_to: hardwareId, hardwareId: tankhardwareId },
|
|
|
|
|
|
|
|
{ $set: updateFields },
|
|
|
|
|
|
|
|
{ new: true }
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const displayMessage = isLoraConnected ? "LoRa connected" : "LoRa not connected";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return reply.send({
|
|
|
|
return reply.send({
|
|
|
|
status_code: 200,
|
|
|
|
status_code: 200,
|
|
|
|
message: displayMessage,
|
|
|
|
message: isLoraConnected ? "LoRa connected" : "LoRa not connected",
|
|
|
|
data: matchedTank,
|
|
|
|
data: matchedTank,
|
|
|
|
lora_connected_status: updateFields.connected_status,
|
|
|
|
lora_connected_status: updateFields.connected_status,
|
|
|
|
connected_lora_date,
|
|
|
|
connected_lora_date: updateFields.connected_lora_date,
|
|
|
|
connected_lora_time,
|
|
|
|
connected_lora_time: updateFields.connected_lora_time,
|
|
|
|
lora_last_check_time
|
|
|
|
lora_last_check_time: updateFields.lora_last_check_time
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
} catch (err) {
|
|
|
|
console.error("Error in getByHardwareAndTankId:", err);
|
|
|
|
console.error("❌ Error in getByHardwareAndTankId:", err);
|
|
|
|
return reply.status(500).send({ error: "Internal Server Error" });
|
|
|
|
return reply.status(500).send({ error: "Internal Server Error" });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.getByHardwareAndTankIdSupport = async (req, reply) => {
|
|
|
|
exports.getByHardwareAndTankIdSupport = async (req, reply) => {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const { hardwareId, tankhardwareId } = req.params;
|
|
|
|
const { hardwareId, tankhardwareId } = req.params;
|
|
|
@ -2449,76 +2439,87 @@ exports.getIotDataByCustomer = async (req, reply) => {
|
|
|
|
return reply.code(400).send({ error: "customerId is required" });
|
|
|
|
return reply.code(400).send({ error: "customerId is required" });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Get all sensors for the customer
|
|
|
|
const sensors = await Insensors.find({ customerId });
|
|
|
|
const sensors = await Insensors.find({ customerId });
|
|
|
|
|
|
|
|
|
|
|
|
if (!sensors.length) {
|
|
|
|
if (!sensors.length) {
|
|
|
|
return reply.code(404).send({ message: "No sensors found for this customer." });
|
|
|
|
return reply.code(404).send({ message: "No sensors found for this customer." });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const masterHardwareIds = [
|
|
|
|
// ✅ Get only master hardware IDs from Insensors directly
|
|
|
|
...new Set(sensors.map(s => s.connected_to?.trim()).filter(Boolean))
|
|
|
|
const masterSensors = sensors.filter(s => s.type === 'master');
|
|
|
|
];
|
|
|
|
const masterHardwareIds = masterSensors.map(m => m.hardwareId?.trim());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Map for masterName/location from Order
|
|
|
|
|
|
|
|
const orders = await Order.find({ customerId }).lean();
|
|
|
|
|
|
|
|
const orderMap = {};
|
|
|
|
|
|
|
|
orders.forEach(order => {
|
|
|
|
|
|
|
|
order.master_connections.forEach(connection => {
|
|
|
|
|
|
|
|
orderMap[connection.hardwareId] = {
|
|
|
|
|
|
|
|
masterName: connection.master_name || null,
|
|
|
|
|
|
|
|
location: connection.location || null
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Prepare final enriched master data
|
|
|
|
const enrichedMasters = await Promise.all(masterHardwareIds.map(async (hardwareId) => {
|
|
|
|
const enrichedMasters = await Promise.all(masterHardwareIds.map(async (hardwareId) => {
|
|
|
|
const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
|
|
|
|
const latestRecord = await IotData.findOne({ hardwareId }).sort({ date: -1 }).lean();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const orderInfo = orderMap[hardwareId] || {};
|
|
|
|
|
|
|
|
|
|
|
|
if (!latestRecord) {
|
|
|
|
if (!latestRecord) {
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
hardwareId,
|
|
|
|
hardwareId,
|
|
|
|
message: "No IoT data found",
|
|
|
|
message: "No IoT data found",
|
|
|
|
|
|
|
|
masterName: orderInfo.masterName ?? null,
|
|
|
|
|
|
|
|
location: orderInfo.location ?? null,
|
|
|
|
tanks: []
|
|
|
|
tanks: []
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Use timestamp to check GSM connection
|
|
|
|
// ✅ Check GSM status
|
|
|
|
const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata");
|
|
|
|
const indiaTime = moment.tz(latestRecord.date, "Asia/Kolkata");
|
|
|
|
const now = moment.tz("Asia/Kolkata");
|
|
|
|
const now = moment.tz("Asia/Kolkata");
|
|
|
|
const diffInMinutes = now.diff(indiaTime, "minutes");
|
|
|
|
const diffInMinutes = now.diff(indiaTime, "minutes");
|
|
|
|
const gsmConnected = diffInMinutes <= 1;
|
|
|
|
const gsmConnected = diffInMinutes <= 1;
|
|
|
|
|
|
|
|
|
|
|
|
const message = gsmConnected ? "GSM is connected" : "GSM is not connected";
|
|
|
|
const message = gsmConnected ? "GSM is connected" : "GSM is not connected";
|
|
|
|
|
|
|
|
|
|
|
|
// Get all connected slaves
|
|
|
|
// ✅ Get slaves connected to this master
|
|
|
|
const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId);
|
|
|
|
const connectedSlaves = sensors.filter(sensor => sensor.connected_to?.trim() === hardwareId);
|
|
|
|
|
|
|
|
|
|
|
|
// Enrich tanks
|
|
|
|
// ✅ Prepare tank info
|
|
|
|
let tanks = connectedSlaves.map(slave => {
|
|
|
|
const tanks = connectedSlaves.map(slave => {
|
|
|
|
const slaveId = slave.hardwareId?.trim();
|
|
|
|
const slaveId = slave.hardwareId?.trim();
|
|
|
|
const matchedTank = latestRecord.tanks.find(tank => tank.tankhardwareId === slaveId);
|
|
|
|
const matchedTank = latestRecord.tanks?.find(t => t.tankhardwareId === slaveId);
|
|
|
|
|
|
|
|
|
|
|
|
let loraConnected = false;
|
|
|
|
let loraMessage = "LORA is not connected";
|
|
|
|
let loraMessage = "LORA is not connected"; // Default message for LoRa not connected
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If matchedTank exists and tankHeight is not zero, check LoRa connection
|
|
|
|
|
|
|
|
if (matchedTank?.date && matchedTank.tankHeight !== "0") {
|
|
|
|
if (matchedTank?.date && matchedTank.tankHeight !== "0") {
|
|
|
|
const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata");
|
|
|
|
const tankTime = moment.tz(matchedTank.date, "Asia/Kolkata");
|
|
|
|
const loraDiff = now.diff(tankTime, "minutes");
|
|
|
|
const loraDiff = now.diff(tankTime, "minutes");
|
|
|
|
loraConnected = loraDiff <= 1;
|
|
|
|
loraMessage = loraDiff <= 1 ? "LORA is connected" : "LORA is not connected";
|
|
|
|
loraMessage = loraConnected ? "LORA is connected" : "LORA is not connected";
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
tankhardwareId: slaveId,
|
|
|
|
tankhardwareId: slaveId,
|
|
|
|
tankName: slave.tankName ?? null,
|
|
|
|
tankName: slave.tankName ?? null,
|
|
|
|
tankLocation: slave.tankLocation ?? null,
|
|
|
|
tankLocation: slave.tankLocation ?? null,
|
|
|
|
masterName: slave.masterName ?? null,
|
|
|
|
masterName: orderInfo.masterName ?? null,
|
|
|
|
location: slave.location ?? null,
|
|
|
|
location: orderInfo.location ?? null,
|
|
|
|
loraMessage, // Updated LoRa message
|
|
|
|
loraMessage,
|
|
|
|
latestTankData: matchedTank ?? null
|
|
|
|
latestTankData: matchedTank ?? null
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// ✅ Remove the first tank
|
|
|
|
|
|
|
|
tanks = tanks.slice(1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
hardwareId,
|
|
|
|
hardwareId,
|
|
|
|
message,
|
|
|
|
message,
|
|
|
|
masterName: connectedSlaves[0]?.masterName ?? null,
|
|
|
|
masterName: orderInfo.masterName ?? null,
|
|
|
|
location: connectedSlaves[0]?.location ?? null,
|
|
|
|
location: orderInfo.location ?? null,
|
|
|
|
tanks
|
|
|
|
tanks
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return reply.send({
|
|
|
|
return reply.send({
|
|
|
|
status_code: 200,
|
|
|
|
status_code: 200,
|
|
|
|