|
|
|
|
@ -160,23 +160,53 @@ exports.updateTanksInfo = async (req, reply) => {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//delete selected tank
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.deleteTanksInfo = async (req, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const customerId = req.params.customerId;
|
|
|
|
|
|
|
|
|
|
const tankName = req.query.tankName;
|
|
|
|
|
const { customerId } = req.params;
|
|
|
|
|
const { tankName } = req.query;
|
|
|
|
|
const tankLocation = req.body.tankLocation.toLowerCase();
|
|
|
|
|
const tank = await Tank.findOneAndDelete({ tankName: tankName,customerId:customerId,tankLocation:tankLocation });
|
|
|
|
|
if (!tankName || !tankLocation) {
|
|
|
|
|
return reply.code(400).send({ message: "Tank name and location are required" });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reply.send({ status_code: 200, data: tank});
|
|
|
|
|
// return tank;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
throw boom.boomify(err);
|
|
|
|
|
// Convert tankLocation to lowercase (for case-insensitive match)
|
|
|
|
|
const normalizedTankLocation = tankLocation.toLowerCase();
|
|
|
|
|
|
|
|
|
|
// Find and delete the main tank
|
|
|
|
|
const deletedTank = await Tank.findOneAndDelete({
|
|
|
|
|
customerId,
|
|
|
|
|
tankName,
|
|
|
|
|
tankLocation: normalizedTankLocation
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!deletedTank) {
|
|
|
|
|
return reply.code(404).send({ message: "Tank not found" });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove the deleted tank from inputConnections and outputConnections in all other tanks
|
|
|
|
|
await Tank.updateMany(
|
|
|
|
|
{ customerId },
|
|
|
|
|
{
|
|
|
|
|
$pull: {
|
|
|
|
|
"connections.inputConnections": { inputConnections: tankName },
|
|
|
|
|
"connections.outputConnections": { outputConnections: tankName }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return reply.send({ message: "Tank deleted successfully" });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error deleting tank:", error);
|
|
|
|
|
return reply.code(500).send({ message: "Internal Server Error" });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.getConnectionsInfoOfParticularTank = async (req, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const customerId = req.params.customerId;
|
|
|
|
|
@ -349,6 +379,7 @@ exports.getTanksofParticularInstaller = async (req, reply) => {
|
|
|
|
|
// throw boom.boomify(err);
|
|
|
|
|
// }
|
|
|
|
|
//};
|
|
|
|
|
// const boom = require("@hapi/boom"); // Assuming you are using boom for error handling
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -357,45 +388,49 @@ exports.getTankmotordata = async (req, reply) => {
|
|
|
|
|
const { startDate, stopDate } = req.body;
|
|
|
|
|
const { customerId } = req.params;
|
|
|
|
|
|
|
|
|
|
// Parse the input startDate and stopDate using the desired format
|
|
|
|
|
// const start = moment(startDate, "DD-MMM-YYYY - HH:mm").toDate();
|
|
|
|
|
// const end = moment(stopDate, "DD-MMM-YYYY - HH:mm").toDate();
|
|
|
|
|
// console.log(start,"start",end,"end")
|
|
|
|
|
// Check if the parsed dates are valid
|
|
|
|
|
// Validate and format the input dates
|
|
|
|
|
if (!moment(startDate, "DD-MMM-YYYY - HH:mm", true).isValid() || !moment(stopDate, "DD-MMM-YYYY - HH:mm", true).isValid()) {
|
|
|
|
|
return reply.send({ status_code: 400, message: "Invalid date format" });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert the dates to the correct format for storage or querying (still in UTC)
|
|
|
|
|
// This gives a native JS Date object for querying
|
|
|
|
|
// Convert input dates to ISO 8601 format for Date comparison
|
|
|
|
|
const startISODate = moment(startDate, "DD-MMM-YYYY - HH:mm").toDate();
|
|
|
|
|
const stopISODate = moment(stopDate, "DD-MMM-YYYY - HH:mm").toDate();
|
|
|
|
|
|
|
|
|
|
// Fetch the name from the User collection based on customerId, only from profile
|
|
|
|
|
const user = await User.findOne({ customerId })
|
|
|
|
|
.select("username");
|
|
|
|
|
// Convert input dates to string format for string-based comparison
|
|
|
|
|
const startStringDate = moment(startDate, "DD-MMM-YYYY - HH:mm").format("DD-MMM-YYYY - HH:mm");
|
|
|
|
|
const stopStringDate = moment(stopDate, "DD-MMM-YYYY - HH:mm").format("DD-MMM-YYYY - HH:mm");
|
|
|
|
|
|
|
|
|
|
// Fetch the username based on customerId
|
|
|
|
|
const user = await User.findOne({ customerId }).select("username");
|
|
|
|
|
|
|
|
|
|
if (user) {
|
|
|
|
|
// Get the full name (combine firstName and lastName if available)
|
|
|
|
|
const userName = user.username
|
|
|
|
|
? `${user.username}`
|
|
|
|
|
: "N/A"; // Fallback if no name is found
|
|
|
|
|
|
|
|
|
|
// Construct the query object for motor data based on customerId
|
|
|
|
|
const motorQuery = { customerId };
|
|
|
|
|
|
|
|
|
|
// Fetch motor data for the customerId within the time range
|
|
|
|
|
const motorDataDocs = await MotorData.find(motorQuery)
|
|
|
|
|
.where("startTime")
|
|
|
|
|
.gte(startDate) // Greater than or equal to startDate
|
|
|
|
|
.lte(stopDate) // Less than or equal to stopDate
|
|
|
|
|
.exec();
|
|
|
|
|
const userName = user.username || "N/A";
|
|
|
|
|
|
|
|
|
|
// Query the MotorData collection
|
|
|
|
|
const motorDataDocs = await MotorData.find({
|
|
|
|
|
customerId,
|
|
|
|
|
$or: [
|
|
|
|
|
{
|
|
|
|
|
startTime: { $gte: startISODate, $lte: stopISODate }, // Date-based comparison
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
startTime: { $gte: startStringDate, $lte: stopStringDate }, // String-based comparison
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}).exec();
|
|
|
|
|
|
|
|
|
|
reply.send({
|
|
|
|
|
status_code: 200,
|
|
|
|
|
data: motorDataDocs,
|
|
|
|
|
count: motorDataDocs.length,
|
|
|
|
|
customerName: userName, // Add the username to the response
|
|
|
|
|
customerName: userName,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
reply.send({ status_code: 404, message: "User not found" });
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("Error in getTankmotordata:", err);
|
|
|
|
|
throw boom.boomify(err);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
@ -2678,7 +2713,7 @@ const monitorWaterLevels = async () => {
|
|
|
|
|
const tankLocation = tank.tankLocation; // Assuming tank has a 'location' field
|
|
|
|
|
|
|
|
|
|
// Call the function to check water levels and send notifications
|
|
|
|
|
await checkWaterLevelsAndNotify(customerId, tankName, tankLocation, fcmTokens);
|
|
|
|
|
//await checkWaterLevelsAndNotify(customerId, tankName, tankLocation, fcmTokens);
|
|
|
|
|
} else {
|
|
|
|
|
//console.log(`No FCM tokens found for customerId ${tank.customerId}`);
|
|
|
|
|
}
|
|
|
|
|
@ -2938,11 +2973,11 @@ exports.motorAction = async (req, reply) => {
|
|
|
|
|
console.log(thresholdTime,"thresholdTime")
|
|
|
|
|
console.log("motor stopping because it entered this condition")
|
|
|
|
|
// Emit the threshold time notification
|
|
|
|
|
eventEmitter.emit(
|
|
|
|
|
"sendThresholdTimeNotification",
|
|
|
|
|
fcmToken,
|
|
|
|
|
`Motor has reached its time threshold of ${req.body.manual_threshold_time} minutes and will stop.`
|
|
|
|
|
);
|
|
|
|
|
// eventEmitter.emit(
|
|
|
|
|
// "sendThresholdTimeNotification",
|
|
|
|
|
// fcmToken,
|
|
|
|
|
// `Motor has reached its time threshold of ${req.body.manual_threshold_time} minutes and will stop.`
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
await Tank.updateOne(
|
|
|
|
|
{ customerId, "connections.inputConnections.motor_id": motorId },
|
|
|
|
|
@ -5665,17 +5700,17 @@ client.on('message', async (topic, message) => {
|
|
|
|
|
inputConnection.motor_on_type = "forced_manual";
|
|
|
|
|
inputConnection.startTime = currentTime;
|
|
|
|
|
// Emit motor start notification with tankName
|
|
|
|
|
eventEmitter.emit(
|
|
|
|
|
"sendMotorStartNotification",
|
|
|
|
|
fcmToken, // FCM tokens
|
|
|
|
|
hw_Id, // Motor ID
|
|
|
|
|
inputConnection.water_level || 0, // Water level
|
|
|
|
|
motorTank.blockName || "N/A", // Block name
|
|
|
|
|
tankName, // Tank name
|
|
|
|
|
inputConnection.motor_on_type, // Motor on type
|
|
|
|
|
"threshold", // Stop criteria
|
|
|
|
|
manual_threshold_time // Threshold time in mins
|
|
|
|
|
);
|
|
|
|
|
// eventEmitter.emit(
|
|
|
|
|
// "sendMotorStartNotification",
|
|
|
|
|
// fcmToken, // FCM tokens
|
|
|
|
|
// hw_Id, // Motor ID
|
|
|
|
|
// inputConnection.water_level || 0, // Water level
|
|
|
|
|
// motorTank.blockName || "N/A", // Block name
|
|
|
|
|
// tankName, // Tank name
|
|
|
|
|
// inputConnection.motor_on_type, // Motor on type
|
|
|
|
|
// "threshold", // Stop criteria
|
|
|
|
|
// manual_threshold_time // Threshold time in mins
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -5683,15 +5718,15 @@ client.on('message', async (topic, message) => {
|
|
|
|
|
inputConnection.motor_stop_status = "1";
|
|
|
|
|
|
|
|
|
|
// Emit motor stop notification with tankName
|
|
|
|
|
eventEmitter.emit(
|
|
|
|
|
"sendMotorStopNotification",
|
|
|
|
|
fcmToken, // FCM tokens
|
|
|
|
|
hw_Id, // Motor ID
|
|
|
|
|
inputConnection.water_level || 0, // Water level
|
|
|
|
|
motorTank.blockName || "N/A", // Block name
|
|
|
|
|
tankName, // Tank name
|
|
|
|
|
inputConnection.motor_on_type // Motor on type
|
|
|
|
|
);
|
|
|
|
|
// eventEmitter.emit(
|
|
|
|
|
// "sendMotorStopNotification",
|
|
|
|
|
// fcmToken, // FCM tokens
|
|
|
|
|
// hw_Id, // Motor ID
|
|
|
|
|
// inputConnection.water_level || 0, // Water level
|
|
|
|
|
// motorTank.blockName || "N/A", // Block name
|
|
|
|
|
// tankName, // Tank name
|
|
|
|
|
// inputConnection.motor_on_type // Motor on type
|
|
|
|
|
// );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await motorTank.save(); // Save the updated tank
|
|
|
|
|
@ -6246,14 +6281,193 @@ const calculateConsumptionAndNotify = async () => {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const calculateWaterLevelAndNotify = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const now = moment();
|
|
|
|
|
const sixHoursAgo = moment().subtract(6, "hours");
|
|
|
|
|
|
|
|
|
|
console.log(`Calculating water level between ${sixHoursAgo.format("HH:mm A")} and ${now.format("HH:mm A")}`);
|
|
|
|
|
|
|
|
|
|
const tanks = await Tank.find({});
|
|
|
|
|
|
|
|
|
|
for (const tank of tanks) {
|
|
|
|
|
const {
|
|
|
|
|
customerId,
|
|
|
|
|
tankName,
|
|
|
|
|
tankLocation,
|
|
|
|
|
typeOfWater,
|
|
|
|
|
capacity,
|
|
|
|
|
waterlevel,
|
|
|
|
|
waterlevel_at_midnight,
|
|
|
|
|
} = tank;
|
|
|
|
|
|
|
|
|
|
// ✅ Fix: Remove commas before parsing numbers
|
|
|
|
|
const tankCapacity = parseFloat(capacity.replace(/,/g, '')) || 0;
|
|
|
|
|
const currentWaterLevel = parseFloat(waterlevel.replace(/,/g, '')) || 0;
|
|
|
|
|
const midnightWaterLevel = parseFloat(waterlevel_at_midnight.replace(/,/g, '')) || 0;
|
|
|
|
|
|
|
|
|
|
if (tankCapacity === 0) {
|
|
|
|
|
console.log(`Skipping tank ${tankName} due to zero capacity`);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const currentWaterLevelPercentage = ((currentWaterLevel / tankCapacity) * 100).toFixed(2);
|
|
|
|
|
const waterUsedSinceMidnight = midnightWaterLevel - currentWaterLevel;
|
|
|
|
|
const waterUsedPercentageSinceMidnight = ((waterUsedSinceMidnight / tankCapacity) * 100).toFixed(2);
|
|
|
|
|
|
|
|
|
|
const user = await User.findOne({ customerId });
|
|
|
|
|
if (!user || !user.fcmIds || user.fcmIds.length === 0) {
|
|
|
|
|
console.log(`No FCM tokens for customer: ${customerId}`);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let notificationBody =
|
|
|
|
|
`🛢️ Tank Name: ${tankName}\n` +
|
|
|
|
|
`🏢 Location: ${tankLocation}\n` +
|
|
|
|
|
`💧 Type of Water: ${typeOfWater}\n` +
|
|
|
|
|
`Current Water Level: ${currentWaterLevel} liters (${currentWaterLevelPercentage}%)\n`;
|
|
|
|
|
|
|
|
|
|
await sendNotification(user.fcmIds, "Water Level Update", notificationBody);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log("Water level notifications sent successfully.");
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("Error in water level calculation:", err);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Schedule notifications at 6 AM, 12 PM, 6 PM, and 12 AM
|
|
|
|
|
cron.schedule(
|
|
|
|
|
"0 6,12,18,0 * * *", // Cron expression for the required times
|
|
|
|
|
async () => {
|
|
|
|
|
console.log("Starting scheduled consumption notification task...");
|
|
|
|
|
await calculateConsumptionAndNotify();
|
|
|
|
|
//await calculateConsumptionAndNotify();
|
|
|
|
|
await calculateWaterLevelAndNotify();
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
timezone: "Asia/Kolkata", // Specify the timezone
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// const updateStopTimeFormat = async () => {
|
|
|
|
|
// try {
|
|
|
|
|
// // Find records where stopTime is null or not in the required format
|
|
|
|
|
// const motorDataDocs = await MotorData.find();
|
|
|
|
|
|
|
|
|
|
// for (const doc of motorDataDocs) {
|
|
|
|
|
// // Parse and validate startTime
|
|
|
|
|
// const startTime = moment(doc.startTime, "DD-MMM-YYYY - HH:mm", true);
|
|
|
|
|
// if (!startTime.isValid()) {
|
|
|
|
|
// console.log(`Invalid startTime for record ID: ${doc._id}`);
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Format startTime if it's not already formatted
|
|
|
|
|
// const formattedStartTime = startTime.format("DD-MMM-YYYY - HH:mm");
|
|
|
|
|
|
|
|
|
|
// // Check if stopTime is valid or calculate it
|
|
|
|
|
// let formattedStopTime = null;
|
|
|
|
|
// const stopTime = moment(doc.stopTime, "DD-MMM-YYYY - HH:mm", true);
|
|
|
|
|
|
|
|
|
|
// if (!stopTime.isValid()) {
|
|
|
|
|
// // Calculate stopTime by adding 30 minutes to startTime
|
|
|
|
|
// formattedStopTime = startTime.clone().add(30, "minutes").format("DD-MMM-YYYY - HH:mm");
|
|
|
|
|
// } else {
|
|
|
|
|
// // Format the existing stopTime
|
|
|
|
|
// formattedStopTime = stopTime.format("DD-MMM-YYYY - HH:mm");
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // Update the document if startTime or stopTime is not correctly formatted
|
|
|
|
|
// if (doc.startTime !== formattedStartTime || doc.stopTime !== formattedStopTime) {
|
|
|
|
|
// await MotorData.updateOne(
|
|
|
|
|
// { _id: doc._id },
|
|
|
|
|
// {
|
|
|
|
|
// $set: {
|
|
|
|
|
// startTime: formattedStartTime,
|
|
|
|
|
// stopTime: formattedStopTime,
|
|
|
|
|
// },
|
|
|
|
|
// }
|
|
|
|
|
// );
|
|
|
|
|
// console.log(`Updated record ID: ${doc._id}`);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// console.log("StopTime format update completed.");
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// console.error("Error updating stopTime format:", err);
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// // Call the function to update stopTime
|
|
|
|
|
// updateStopTimeFormat();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.updatetankstatus = async (req, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { customerId } = req.params;
|
|
|
|
|
const { tankName, tankLocation, status } = req.body;
|
|
|
|
|
|
|
|
|
|
if (!["active", "inactive"].includes(status)) {
|
|
|
|
|
return reply.code(400).send({ message: "Invalid status value" });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find the main tank
|
|
|
|
|
const mainTank = await Tank.findOneAndUpdate(
|
|
|
|
|
{ customerId, tankName, tankLocation },
|
|
|
|
|
{ $set: { status } },
|
|
|
|
|
{ new: true }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (!mainTank) {
|
|
|
|
|
return reply.code(404).send({ message: "Tank not found" });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update status in related outputConnections tanks
|
|
|
|
|
await Tank.updateMany(
|
|
|
|
|
{
|
|
|
|
|
customerId,
|
|
|
|
|
"connections.outputConnections.outputConnections": tankName,
|
|
|
|
|
},
|
|
|
|
|
{ $set: { "connections.outputConnections.$.status": status } }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Update status in related inputConnections tanks
|
|
|
|
|
await Tank.updateMany(
|
|
|
|
|
{
|
|
|
|
|
customerId,
|
|
|
|
|
"connections.inputConnections.inputConnections": tankName,
|
|
|
|
|
},
|
|
|
|
|
{ $set: { "connections.inputConnections.$.status": status } }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return reply.send({ message: "Tank status updated successfully" });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error updating tank status:", error);
|
|
|
|
|
return reply.code(500).send({ message: "Internal Server Error" });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exports.listofactiveandinactivetankstatus = async (req, reply) => {
|
|
|
|
|
try {
|
|
|
|
|
const { customerId } = req.params;
|
|
|
|
|
const { status } = req.query;
|
|
|
|
|
|
|
|
|
|
if (!["active", "inactive"].includes(status)) {
|
|
|
|
|
return reply.code(400).send({ message: "Invalid status value" });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find tanks based on customerId and status
|
|
|
|
|
const tanks = await Tank.find({ customerId, status });
|
|
|
|
|
|
|
|
|
|
return reply.send({ tanks });
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error fetching tank list:", error);
|
|
|
|
|
return reply.code(500).send({ message: "Internal Server Error" });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|