diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index c77cc39f..daa66826 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -6926,6 +6926,44 @@ exports.sendUserSetNotifications = async (request, reply) => { } }; +exports.sendUserSetLowWaterNotificationsSwitch = async (request, reply) => { + const { customerId, lowWaterAlert } = request.body; + + try { + const user = await User.findOneAndUpdate( + { customerId }, + { lowWaterAlert}, + { new: true, upsert: true } // Create user if not exists + ); + + console.log(`User ${customerId} updated: Allowed - ${lowWaterAlert}`); + + return reply.send({ success: true, user }); + } catch (error) { + console.error("Error setting notification time:", error); + return reply.status(500).send({ success: false, message: "Internal server error" }); + } +}; + +exports.sendUserSetCriticallyLowWaterNotificationsSwitch = async (request, reply) => { + const { customerId, criticalLowWaterAlert } = request.body; + + try { + const user = await User.findOneAndUpdate( + { customerId }, + { criticalLowWaterAlert}, + { new: true, upsert: true } // Create user if not exists + ); + + console.log(`User ${customerId} updated: Allowed - ${criticalLowWaterAlert}`); + + return reply.send({ success: true, user }); + } catch (error) { + console.error("Error setting notification time:", error); + return reply.status(500).send({ success: false, message: "Internal server error" }); + } +}; + // const calculateWaterLevelAndNotify = async () => { // try { // const now = moment(); @@ -7048,6 +7086,141 @@ const calculateWaterLevelAndNotify = async () => { } }; +const calculateLowWaterLevelAndNotify = async () => { + try { + const now = moment(); + const currentTime = now.format("HH:mm"); // Current time in HH:mm format + + console.log(`Current time: ${currentTime}`); + + // Get all users who have allowed notifications and have set a notification time + const users = await User.find({ lowWaterAlert: true}); + + if (users.length === 0) { + console.log("No users to notify at this time."); + return; + } + + for (const user of users) { + const { customerId, fcmIds } = user; + + if (!Array.isArray(fcmIds) || fcmIds.length === 0) { + console.log(`No valid FCM tokens for customer ID: ${customerId}`); + continue; + } + + // Get tanks associated with the user + const tanks = await Tank.find({ customerId }); + + for (const tank of tanks) { + const { + tankName, + tankLocation, + typeOfWater, + capacity, + waterlevel, + waterlevel_at_midnight, + } = tank; + + // 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); + + let notificationBody = + `🛢️ Tank Name: ${tankName}\n` + + `🏢 Location: ${tankLocation}\n` + + `💧 Type of Water: ${typeOfWater}\n` + + `Current Water Level: ${currentWaterLevel} liters (${currentWaterLevelPercentage}%)\n`; + + await sendNotification(customerId, fcmIds, "Low Water Level Update", notificationBody); + console.log("Notification sent for tank:", tankName); + } + } + + console.log("Water level notifications processed."); + } catch (err) { + console.error("Error in water level calculation:", err); + } +}; + +const calculateCriticalLowWaterLevelAndNotify = async () => { + try { + const now = moment(); + const currentTime = now.format("HH:mm"); // Current time in HH:mm format + + console.log(`Current time: ${currentTime}`); + + // Get all users who have allowed notifications and have set a notification time + const users = await User.find({ criticalLowWaterAlert: true}); + + if (users.length === 0) { + console.log("No users to notify at this time."); + return; + } + + for (const user of users) { + const { customerId, fcmIds } = user; + + if (!Array.isArray(fcmIds) || fcmIds.length === 0) { + console.log(`No valid FCM tokens for customer ID: ${customerId}`); + continue; + } + + // Get tanks associated with the user + const tanks = await Tank.find({ customerId }); + + for (const tank of tanks) { + const { + tankName, + tankLocation, + typeOfWater, + capacity, + waterlevel, + waterlevel_at_midnight, + } = tank; + + // 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); + + let notificationBody = + `🛢️ Tank Name: ${tankName}\n` + + `🏢 Location: ${tankLocation}\n` + + `💧 Type of Water: ${typeOfWater}\n` + + `Current Water Level: ${currentWaterLevel} liters (${currentWaterLevelPercentage}%)\n`; + + await sendNotification(customerId, fcmIds, "Critical Low Water Level Update", notificationBody); + console.log("Notification sent for tank:", tankName); + } + } + + console.log("Water level notifications processed."); + } catch (err) { + console.error("Error in water level calculation:", err); + } +}; + + // Run the function every minute to check if any user needs a notification cron.schedule('* * * * *', async () => { console.log("Checking for user notification times..."); @@ -7057,6 +7230,13 @@ cron.schedule('* * * * *', async () => { }); +cron.schedule('0 * * * *', async () => { + console.log("Checking for user notification times..."); + await calculateLowWaterLevelAndNotify(); + await calculateCriticalLowWaterLevelAndNotify(); +}, { + timezone: "Asia/Kolkata", +}); // Schedule notifications at 6 AM, 12 PM, 6 PM, and 12 AM // cron.schedule( diff --git a/src/models/User.js b/src/models/User.js index 65a844e2..abce4d82 100644 --- a/src/models/User.js +++ b/src/models/User.js @@ -132,8 +132,10 @@ const userSchema = new mongoose.Schema( type: Date, default: null, // Initially, no notifications sent }, - notificationTime: { type: String }, // Store user preferred notification time in HH:mm format + notificationTime: { type: String }, allowNotifications: { type: Boolean, default: true }, + lowWaterAlert: { type: Boolean, default: true }, + criticalLowWaterAlert: { type: Boolean, default: true }, createdAt: { type: Date, diff --git a/src/routes/tanksRoute.js b/src/routes/tanksRoute.js index 1e4611d5..ed534948 100644 --- a/src/routes/tanksRoute.js +++ b/src/routes/tanksRoute.js @@ -1343,6 +1343,43 @@ module.exports = function (fastify, opts, next) { handler: tanksController.sendUserSetNotifications, }); + fastify.route({ + method: "POST", + url: "/api/sendNotificationLowWaterLevel", + schema: { + tags: ["Tank"], + summary: "This is for Send low water level alert notification", + body: { + type: "object", + properties: { + customerId: { type: "string" }, + lowWaterAlert: { type: "boolean" }, + }, + required: ["customerId", "lowWaterAlert"], // Ensures all fields are required + }, + security: [{ basicAuth: [] }], + }, + handler: tanksController.sendUserSetLowWaterNotificationsSwitch, + }); + + fastify.route({ + method: "POST", + url: "/api/sendNotificationCriticallyWaterLevel", + schema: { + tags: ["Tank"], + summary: "This is for Send critically low water level alert notification", + body: { + type: "object", + properties: { + customerId: { type: "string" }, + criticalLowWaterAlert: { type: "boolean" }, + }, + required: ["customerId", "criticalLowWaterAlert"], // Ensures all fields are required + }, + security: [{ basicAuth: [] }], + }, + handler: tanksController.sendUserSetCriticallyLowWaterNotificationsSwitch, + }); fastify.route({ method: "POST",