From 8eaad995a97a201865f5287a18e2fab8333dd35b Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Tue, 28 Jan 2025 17:16:02 +0530 Subject: [PATCH 1/5] chnages --- src/controllers/tanksController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index cd0f4bf3..d04ab5d7 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -2678,7 +2678,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}`); } From bc8c5e750c88149a4acc5b6c33d91a851b4fadc1 Mon Sep 17 00:00:00 2001 From: Varun Date: Wed, 29 Jan 2025 10:22:24 +0530 Subject: [PATCH 2/5] changes in get motordata --- src/controllers/tanksController.js | 152 ++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 47 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index b09ceb9a..1cf85216 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -349,6 +349,7 @@ exports.getTanksofParticularInstaller = async (req, reply) => { // throw boom.boomify(err); // } //}; +// const boom = require("@hapi/boom"); // Assuming you are using boom for error handling @@ -356,46 +357,50 @@ exports.getTankmotordata = async (req, reply) => { try { 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 - - // Convert the dates to the correct format for storage or querying (still in UTC) - // This gives a native JS Date object for querying - // Fetch the name from the User collection based on customerId, only from profile - const user = await User.findOne({ customerId }) - .select("username"); + // 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" }); + } - 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 + // 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(); - // Construct the query object for motor data based on customerId - const motorQuery = { customerId }; + // 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 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(); + // Fetch the username based on customerId + const user = await User.findOne({ customerId }).select("username"); + + if (user) { + 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); } }; @@ -415,7 +420,7 @@ exports.updateTanklevels = async (req, reply) => { for (const tank of tanks) { const tankId = tank._id; - const tank_name = tank.tankName + const tank_name = tank.tankName let capacity = parseInt(tank.capacity.replace(/,/g, ''), 10); //let waterLevel = parseInt(tank.waterlevel.replace(/,/g, ''), 10); @@ -5665,17 +5670,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 +5688,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 @@ -6257,3 +6262,56 @@ cron.schedule( 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(); From 6515647b9e30ebb85cdee3f76f2b07dfe7b4f901 Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Wed, 29 Jan 2025 10:48:08 +0530 Subject: [PATCH 3/5] evey six hours report tanks --- src/controllers/tanksController.js | 62 +++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index d04ab5d7..1b7043c2 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -6246,14 +6246,72 @@ 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 } -); +); \ No newline at end of file From f3a120c1d9eef02bec7aaabe4f89bbdffdc23113 Mon Sep 17 00:00:00 2001 From: Varun Date: Wed, 29 Jan 2025 11:05:47 +0530 Subject: [PATCH 4/5] added acxtive and inactive in tanks --- src/controllers/tanksController.js | 117 ++++++++++++++++++++++++++--- src/models/tanks.js | 7 +- src/routes/tanksRoute.js | 64 ++++++++++++++++ 3 files changed, 176 insertions(+), 12 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index 2ed19ea1..5078c5f8 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -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; @@ -6315,3 +6345,72 @@ cron.schedule( // // 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" }); + } +}; diff --git a/src/models/tanks.js b/src/models/tanks.js index d53a79cb..4c42da8e 100644 --- a/src/models/tanks.js +++ b/src/models/tanks.js @@ -63,7 +63,7 @@ const tanksSchema = new mongoose.Schema({ notificationSentVeryHigh: { type: Boolean }, notificationSentHigh: { type: Boolean }, all_motor_status: { type: Boolean }, - + status:{ type: String, default: "active" }, connections: { source: { type: String }, @@ -81,7 +81,7 @@ const tanksSchema = new mongoose.Schema({ water_level: { type: String, default: null }, manual_threshold_percentage: { type: String, default: "90" }, manual_threshold_time: { type: String, default: null }, - + status:{ type: String, default: "active" }, stop_threshold_time: { type: String, default: null }, threshold_type: { type: String, default: "percentage" }, startTime: { type: String, default: null }, @@ -103,7 +103,8 @@ const tanksSchema = new mongoose.Schema({ manual_threshold_percentage: { type: String, default: "90" }, manual_threshold_time: { type: String, default: null }, threshold_type: { type: String, default: "percentage" }, - waterlevelPercentage: { type: String, default: null } + waterlevelPercentage: { type: String, default: null } , + status:{ type: String, default: "active" }, } ], inputWaterlevelPercentage: { type: String, default: null }, diff --git a/src/routes/tanksRoute.js b/src/routes/tanksRoute.js index 4a904302..3ee25576 100644 --- a/src/routes/tanksRoute.js +++ b/src/routes/tanksRoute.js @@ -1231,6 +1231,70 @@ module.exports = function (fastify, opts, next) { }); + fastify.route({ + method: "PUT", + url: "/api/updatetankstatus/:customerId", + schema: { + tags: ["Tank"], + summary: "This is for updating tank status to active or inactive", + params: { + required: ["customerId"], + type: "object", + properties: { + customerId: { + type: "string", + description: "customerId", + }, + }, + }, + + body: { + type: "object", + // required: ['phone'], + properties: { + tankName:{ type: "string" }, + tankLocation:{type:"string"}, + status:{type:"string"}, + + + }, + }, + security: [ + { + basicAuth: [], + }, + ], + }, + //preHandler: fastify.auth([fastify.authenticate]), + handler: tanksController.updatetankstatus, + }); + + + fastify.route({ + method: "GET", + url: "/api/listofactiveandinactivetankstatus/:customerId", + schema: { + tags: ["Tank"], + summary: "Get list of active or inactive tanks", + params: { + required: ["customerId"], + type: "object", + properties: { + customerId: { type: "string", description: "Customer ID" }, + }, + }, + querystring: { + type: "object", + properties: { + status: { type: "string", enum: ["active", "inactive"] }, + }, + }, + security: [{ basicAuth: [] }], + }, + handler: tanksController.listofactiveandinactivetankstatus, + }); + + next(); } From 55aa30a21df07e978d9bcec05a1303bed605875a Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Wed, 29 Jan 2025 11:13:29 +0530 Subject: [PATCH 5/5] changes --- src/controllers/tanksController.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index 8bb25691..9b9e1e14 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -2973,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 },