From e8885fed3a5f9eafdf8a778ca9de673cf19383fd Mon Sep 17 00:00:00 2001 From: Naidu Date: Tue, 8 Oct 2024 04:15:55 -0700 Subject: [PATCH 1/7] admin ,sales and store login signup --- src/controllers/admincontroller.js | 402 +++++++++++++++++++++++++---- src/models/admin.js | 30 ++- src/routes/adminRoute.js | 167 ++++++++++-- 3 files changed, 519 insertions(+), 80 deletions(-) diff --git a/src/controllers/admincontroller.js b/src/controllers/admincontroller.js index 5148f1f5..c389ef56 100644 --- a/src/controllers/admincontroller.js +++ b/src/controllers/admincontroller.js @@ -3,9 +3,28 @@ const boom = require("boom"); const jwt = require('jsonwebtoken') const bcrypt = require('bcrypt') + const fastify = require("fastify"); const { Tank, MotorData, IotData } = require('../models/tanks') +const JWT_SECRET = 'your-secret-key'; + +async function generateCustomerId() { + let customerId; + let isUnique = false; + + while (!isUnique) { + // Generate a random number or string for the customer ID + customerId = Math.floor(1000 + Math.random() * 9000).toString(); // Generates a random number between 1000 and 9999 + + // Check for uniqueness in the Admin collection + const existingAdmin = await Admin.findOne({ customerId }); + if (!existingAdmin) { + isUnique = true; // Exit the loop if the customer ID is unique + } + } + return customerId; +} // exports.adminSignUp = async (request, reply) => { @@ -39,73 +58,355 @@ const { Tank, MotorData, IotData } = require('../models/tanks') // } // } -exports.adminSignUp = async (request, reply) => { +// exports.adminSignUp = async (request, reply) => { - try { - const { email, password } = request.body +// try { +// const { email, password } = request.body - // Check if the email address is valid - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - if (!emailRegex.test(email)) { - return reply.status(400).send({ message: 'Invalid email address' }) - } +// // Check if the email address is valid +// const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ +// if (!emailRegex.test(email)) { +// return reply.status(400).send({ message: 'Invalid email address' }) +// } - // Check if an admin with the same email address already exists - const existingAdmin = await Admin.findOne({ email }) +// // Check if an admin with the same email address already exists +// const existingAdmin = await Admin.findOne({ email }) - if (existingAdmin) { - return reply.status(400).send({ message: 'Email already registered' }) - } +// if (existingAdmin) { +// return reply.status(400).send({ message: 'Email already registered' }) +// } - // Hash the password using bcrypt - const hashedPassword = await bcrypt.hash(password, 10) +// // Hash the password using bcrypt +// const hashedPassword = await bcrypt.hash(password, 10) - // Create a new admin object with the hashed password - const admin = new Admin({ email, password: hashedPassword }) +// // Create a new admin object with the hashed password +// const admin = new Admin({ email, password: hashedPassword }) - // Save the new admin to the database - await admin.save() +// // Save the new admin to the database +// await admin.save() - // Generate a JWT token for the new admin - // const token = jwt.sign({ email: admin.email }, 'secret') +// // Generate a JWT token for the new admin +// // const token = jwt.sign({ email: admin.email }, 'secret') - // // Return the token to the client - // return { token } - reply.send({message : "Admin Account Created Sucessfully"}) - } catch (err) { - reply.status(500).send({ message: err.message }) - } - } +// // // Return the token to the client +// // return { token } +// reply.send({message : "Admin Account Created Sucessfully"}) +// } catch (err) { +// reply.status(500).send({ message: err.message }) +// } +// } - exports.adminLogin = async (request, reply) => { - try { - const { email, password } = request.body +// exports.adminLogin = async (request, reply) => { +// try { +// const { email, password } = request.body - // Check if an admin with the email address exists - const admin = await Admin.findOne({ email }) +// // Check if an admin with the email address exists +// const admin = await Admin.findOne({ email }) - if (!admin) { - return reply.status(401).send({ message: 'Invalid email or password' }) - } +// if (!admin) { +// return reply.status(401).send({ message: 'Invalid email or password' }) +// } - // Compare the password entered by the user with the hashed password stored in the database - const isPasswordValid = await bcrypt.compare(password, admin.password) +// // Compare the password entered by the user with the hashed password stored in the database +// const isPasswordValid = await bcrypt.compare(password, admin.password) - if (!isPasswordValid) { - return reply.status(401).send({ message: 'Invalid email or password' }) - } +// if (!isPasswordValid) { +// return reply.status(401).send({ message: 'Invalid email or password' }) +// } - // Generate a JWT token for the authenticated admin - const token = jwt.sign({ email: admin.email }, 'secret') +// // Generate a JWT token for the authenticated admin +// const token = jwt.sign({ email: admin.email }, 'secret') - // Return the token to the client - return { token } - } catch (err) { - reply.status(500).send({ message: err.message }) - } +// // Return the token to the client +// return { token } +// } catch (err) { +// reply.status(500).send({ message: err.message }) +// } +// } + + +// Admin Sign-Up Function +// exports.adminSignUp = async (request, reply) => { +// try { +// const { phone,username, password } = request.body; + +// // Check if the email address is valid +// // const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; +// // if (!emailRegex.test(email)) { +// // return reply.status(400).send({ message: 'Invalid email address' }); +// // } +// if (!username || username.trim() === '') { +// return reply.status(400).send({ message: 'Username is required' }); +// } + + +// // Check if an admin with the same email address already exists +// const existingAdminUsername = await Admin.findOne({ username }); +// const existingAdmin = await Admin.findOne({ phone }); +// if (existingAdmin) { +// return reply.status(400).send({ message: 'phone already registered' }); +// } +// if (existingAdminUsername) { +// return reply.status(400).send({ message: 'Username already registered' }); +// } + +// // Hash the password using bcrypt +// const hashedPassword = await bcrypt.hash(password, 10); + +// // Create a new admin object with the hashed password +// const admin = new Admin({ phone,username, password: hashedPassword }); + +// // Save the new admin to the database +// await admin.save(); + +// reply.send({ message: 'Admin Account Created Successfully' }); +// } catch (err) { +// reply.status(500).send({ message: err.message }); +// } +// }; + +exports.adminSignUp = async (request, reply) => { + try { + const { phone, username, password, role } = request.body; + + if (!username || username.trim() === '') { + return reply.status(400).send({ message: 'Username is required' }); + } + + // Validate role + if (!['admin', 'sales', 'store'].includes(role)) { + return reply.status(400).send({ message: 'Invalid role. Must be either admin, sales, or store' }); + } + + + + // Check if an admin with the same phone number or username already exists + const existingAdminUsername = await Admin.findOne({ username }); + const existingAdmin = await Admin.findOne({ phone }); + + if (existingAdmin) { + return reply.status(400).send({ message: 'Phone already registered' }); + } + if (existingAdminUsername) { + return reply.status(400).send({ message: 'Username already registered' }); + } + + // Hash the password using bcrypt + const hashedPassword = await bcrypt.hash(password, 10); + + const c_id = await generateCustomerId(); // Assuming you have this function defined elsewhere + const building = 'ADMIN'; // You can customize this logic to derive from a parameter or a default value + const customerId = `AWSU${building}${c_id}`; // Construct the customer ID + + // Create a new admin object with the hashed password and role + const admin = new Admin({ phone, username, password: hashedPassword, customerId, role }); + + // Save the new admin to the database + await admin.save(); + + reply.send({ message: 'Admin Account Created Successfully' }); + } catch (err) { + reply.status(500).send({ message: err.message }); + } +}; + + +// Admin Login Function (With Phone Number) +exports.adminLogin = async (request, reply) => { + try { + const { phone, password } = request.body; + + // Check if an admin with the phone number exists + const admin = await Admin.findOne({ phone }); + + if (!admin) { + return reply.status(401).send({ message: 'Invalid phone number or password' }); + } + + // Compare the password entered by the user with the hashed password stored in the database + const isPasswordValid = await bcrypt.compare(password, admin.password); + + if (!isPasswordValid) { + return reply.status(401).send({ message: 'Invalid phone number or password' }); + } + + // Generate a JWT token for the authenticated admin + const token = jwt.sign({ phone: admin.phone, role: 'admin' }, JWT_SECRET, { expiresIn: '1h' }); + + return reply.send({ token }); + } catch (err) { + reply.status(500).send({ message: err.message }); + } +}; + +// Sales and Store Login (Phone and Password) +// exports.salesStoreLogin = async (request, reply) => { +// try { +// const { phone, password } = request.body; + +// // Check if a user (sales or store) with the phone number exists +// const admin = await Admin.findOne({ phone }); + +// if (!admin) { +// return reply.status(401).send({ message: 'Invalid phone number or password' }); +// } + +// // Compare the password entered by the user with the hashed password stored in the database +// const isPasswordValid = await bcrypt.compare(password, admin.password); + +// if (!isPasswordValid) { +// return reply.status(401).send({ message: 'Invalid phone number or password' }); +// } + +// // Generate a JWT token for the authenticated user (with role sales or store) +// const token = jwt.sign({ phone: admin.phone, role: admin.role }, JWT_SECRET, { expiresIn: '1h' }); + +// return reply.send({ token }); +// } catch (err) { +// reply.status(500).send({ message: err.message }); +// } +// }; + +exports.salesStoreLogin = async (request, reply) => { + try { + const { phone, password, role } = request.body; + + // Check if a user (sales or store) with the phone number and role exists + const user = await Admin.findOne({ phone, role }); + + if (!user) { + return reply.status(401).send({ message: 'Invalid phone number, password, or role' }); + } + + // Compare the password entered by the user with the hashed password stored in the database + const isPasswordValid = await bcrypt.compare(password, user.password); + + if (!isPasswordValid) { + return reply.status(401).send({ message: 'Invalid phone number, password, or role' }); + } + + // Generate a JWT token for the authenticated user (with role sales or store) + const token = jwt.sign({ phone: user.phone, role: user.role }, JWT_SECRET, { expiresIn: '1h' }); + + return reply.send({ token }); + } catch (err) { + reply.status(500).send({ message: err.message }); + } +}; + + +exports.getUsersByRole = async (request, reply) => { + try { + const { role } = request.params; + + // Ensure the role is either 'sales' or 'store' + if (!['sales', 'store'].includes(role)) { + return reply.status(400).send({ message: 'Invalid role. Must be either sales or store.' }); + } + + // Find users with the specific role (sales or store) + const users = await Admin.find({ role }); + + // Send back the list of users + reply.send(users); + } catch (err) { + reply.status(500).send({ message: err.message }); } +}; + +exports.getUserByCustomerId = async (request, reply) => { + try { + const { customerId } = request.params; + + // Check if customerId is provided + if (!customerId) { + return reply.status(400).send({ message: 'Customer ID is required' }); + } + + // Fetch the user from the database + const user = await Admin.findOne({ customerId }); + + // If user not found, return a 404 response + if (!user) { + return reply.status(404).send({ message: 'User not found' }); + } + + // Return the user data + return reply.send(user); + } catch (err) { + return reply.status(500).send({ message: err.message }); + } +}; + + +// Create Sales/Store User (Admin Only) +// exports.createUser = async (request, reply) => { +// const { phone, password, role } = request.body; + +// // Validate role (only sales or store) +// if (!['sales', 'store'].includes(role)) { +// return reply.status(400).send({ message: 'Invalid role. Must be either sales or store' }); +// } + +// try { +// const existingUser = await Admin.findOne({ phone }); + +// if (existingUser) { +// return reply.status(400).send({ message: 'User with this phone number already exists' }); +// } + +// // Hash the password +// const hashedPassword = await bcrypt.hash(password, 10); + +// // Create the new user +// const newUser = new Admin({ +// phone, +// password: hashedPassword, +// role, +// }); + +// await newUser.save(); + +// return reply.send({ message: 'User created successfully' }); +// } catch (err) { +// reply.status(500).send({ message: err.message }); +// } +// }; + +exports.createUser = async (request, reply) => { + const { phone, password, role } = request.body; + + // Validate role (only sales or store) + if (!['sales', 'store'].includes(role)) { + return reply.status(400).send({ message: 'Invalid role. Must be either sales or store' }); + } + + try { + const existingUser = await Admin.findOne({ phone }); + + if (existingUser) { + return reply.status(400).send({ message: 'User with this phone number already exists' }); + } + + // Hash the password + const hashedPassword = await bcrypt.hash(password, 10); + + // Create the new user + const newUser = new Admin({ + phone, + password: hashedPassword, + role, + }); + + await newUser.save(); + return reply.send({ message: 'User created successfully' }); + } catch (err) { + reply.status(500).send({ message: err.message }); + } +}; + @@ -120,8 +421,3 @@ exports.adminSignUp = async (request, reply) => { } } - - - - - \ No newline at end of file diff --git a/src/models/admin.js b/src/models/admin.js index 29de8268..2a962f4c 100644 --- a/src/models/admin.js +++ b/src/models/admin.js @@ -1,18 +1,40 @@ const mongoose = require('mongoose') + + const adminSchema = new mongoose.Schema({ - email: { + + phone: { + type: String, + required: true, + //unique: true, + }, + + username: { type: String, required: true, unique: true, - lowercase: true }, password: { type: String, required: true - } + }, + role: { + type: String, + enum: ['admin', 'sales', 'store'], + default: 'sales', + }, + customerId: { + type: String, + required: true, // Customer ID is now required + unique: true, + }, + date: { + type: Date, + default: Date.now, + }, }) const Admin = mongoose.model('Admin', adminSchema) -module.exports = Admin +module.exports = Admin \ No newline at end of file diff --git a/src/routes/adminRoute.js b/src/routes/adminRoute.js index cbf3eff6..54629f06 100644 --- a/src/routes/adminRoute.js +++ b/src/routes/adminRoute.js @@ -3,31 +3,58 @@ const adminController = require('../controllers/admincontroller') module.exports = function (fastify, opts, next) { +// fastify.route({ +// method: "POST", +// url: "/api/adminSignup", +// schema: { +// tags: ["Admin"], +// description: "This is for cretae New Admin Account", +// summary: "This is for cretae New Admin Account", +// body: { +// type: "object", +// properties: { +// phone : { type: "string" }, +// password: { type: "string" }, +// username:{type:"string"}, +// }, +// }, +// security: [ +// { +// basicAuth: [], +// }, +// ], +// }, + +// handler: adminController.adminSignUp, + +// }); + fastify.route({ - method: "POST", - url: "/api/adminSignup", - schema: { - tags: ["Admin"], - description: "This is for cretae New Admin Account", - summary: "This is for cretae New Admin Account", - body: { - type: "object", - properties: { - email: { type: "string" }, - password: { type: "string" }, - - }, + method: "POST", + url: "/api/adminSignup", + schema: { + tags: ["Admin"], + description: "This is for creating a new Admin/sales/store Account", + summary: "This is for creating a new Admin/sales/store Account", + body: { + type: "object", + required: ["phone", "username", "password", "role"], // Add role to required fields + properties: { + phone: { type: "string" }, + password: { type: "string" }, + username: { type: "string" }, + role: { type: "string", enum: ["admin", "sales", "store"] }, // Define allowed roles }, - security: [ - { - basicAuth: [], - }, - ], }, + security: [ + { + basicAuth: [], + }, + ], + }, + handler: adminController.adminSignUp, +}); - handler: adminController.adminSignUp, - - }); fastify.post("/api/adminLogin", { schema: { @@ -36,9 +63,9 @@ fastify.route({ summary: "This is for Login Admin", body: { type: "object", - required: ["email", "password"], + required: ["phone", "password"], properties: { - email: { type: "string" }, + phone : { type: "string" }, password: { type: "string" }, }, }, @@ -46,6 +73,100 @@ fastify.route({ handler: adminController.adminLogin, }); +fastify.post("/api/salesStoreLogin", { + schema: { + description: "Login for sales/store users", + tags: ["Sales/Store Login"], + summary: "Login for sales/store users", + body: { + type: "object", + required: ["phone", "password", "role"], + properties: { + phone : { type: "string" }, + password: { type: "string" }, + role: { type: "string", enum: ["sales", "store"] } + }, + }, + }, + handler: adminController.salesStoreLogin, +}); + + +fastify.get("/api/getUsersByRole/:role", { + schema: { + description: "Get list of users by role (sales/store)", + tags: ["Sales/Store Users"], + summary: "Get list of users by role", + params: { + type: "object", + properties: { + role: { type: "string", enum: ["sales", "store"] }, + }, + required: ["role"], + }, + response: { + 200: { + type: "array", + items: { + type: "object", + properties: { + phone: { type: "string" }, + username: { type: "string" }, + role: { type: "string" }, + date: { type: "string", format: "date-time" } + } + } + } + } + }, + handler: adminController.getUsersByRole, +}); + +fastify.route({ + method: "GET", + url: "/api/users/:customerId", // Use path parameters for customerId + schema: { + tags: ["Admin"], + description: "Retrieve user information by customerId", + summary: "Get user by customerId", + params: { + type: "object", + required: ["customerId"], + properties: { + customerId: { type: "string" }, + }, + }, + security: [ + { + basicAuth: [], + }, + ], + }, + handler: adminController.getUserByCustomerId, // Link the handler function +}); + + +// fastify.post("/api/createUser", { +// schema: { +// description: "This is for Create sale/store", +// tags: ["createUser for sale/sore"], +// summary: "This is for Create sale/store", +// body: { +// type: "object", +// required: ["phone", "password", "role"], +// properties: { +// phone : { type: "string" }, +// password: { type: "string" }, +// role: { type: "string", enum: ["sales", "store"] } +// }, +// }, +// }, +// handler: adminController.createUser, +// }); + + + + fastify.post("/api/integratingHardwareidToTank", { schema: { description: "This is for integrating hardwareId with tank", From e28bfa1effef800569338555bc1e3ce21dfe925c Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Wed, 9 Oct 2024 17:50:43 +0530 Subject: [PATCH 2/7] notifications --- node_modules/.package-lock.json | 2 +- package-lock.json | 1 + package.json | 1 + src/controllers/tanksController.js | 459 +++++++++++++++++++++++++---- 4 files changed, 404 insertions(+), 59 deletions(-) diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index a7fd7a7a..b90c5a48 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -1,7 +1,7 @@ { "name": "armintatankapi", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "node_modules/@adminjs/design-system": { diff --git a/package-lock.json b/package-lock.json index 8c151ae1..b74fdaf5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "csvjson": "^5.1.0", "csvtojson": "^2.0.10", "email-validator": "^2.0.4", + "events": "^3.3.0", "exceljs": "^4.3.0", "fastify": "^3.29.5", "fastify-auth": "^1.0.1", diff --git a/package.json b/package.json index 56e6b6c6..e7f99557 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "csvjson": "^5.1.0", "csvtojson": "^2.0.10", "email-validator": "^2.0.4", + "events": "^3.3.0", "exceljs": "^4.3.0", "fastify": "^3.29.5", "fastify-auth": "^1.0.1", diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index 0444d088..5934495a 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -10,7 +10,8 @@ const fastify = require("fastify")({ const cron = require('node-cron'); const moment = require('moment'); - +const EventEmitter = require('events'); +const eventEmitter = new EventEmitter(); async function deleteOldRecords() { const SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000; const sevenDaysAgo = new Date(Date.now() - SEVEN_DAYS_IN_MILLISECONDS); @@ -1320,28 +1321,81 @@ admin.initializeApp({ credential: admin.credential.cert(serviceAccount), }); +// // Handle motor start event +// eventEmitter.on('motorStart', async (fcmTokens) => { +// await sendNotification(fcmTokens, 'Motor Started', 'The motor has been started successfully.'); +// }); + +// // Handle motor stop event +// eventEmitter.on('motorStop', async (fcmTokens) => { +// await sendNotification(fcmTokens, 'Motor Stopped', 'The motor has been stopped successfully.'); +// }); + +// // Handle low water level event +// eventEmitter.on('lowWaterLevel', async (fcmTokens) => { +// await sendNotification(fcmTokens, 'Low Water Level', 'The water level is below 20%.'); +// }); + +// // Handle high water level event +// eventEmitter.on('highWaterLevel', async (fcmTokens) => { +// await sendNotification(fcmTokens, 'High Water Level', 'The water level has reached above 90%.'); +// }); + +// Handle motor start event with timestamp +eventEmitter.on('motorStart', async (fcmTokens, timestamp) => { + await sendNotification(fcmTokens, 'Motor Started', `The motor has been started successfully at ${timestamp}.`); +}); + +// Handle motor stop event with timestamp +eventEmitter.on('motorStop', async (fcmTokens, timestamp) => { + await sendNotification(fcmTokens, 'Motor Stopped', `The motor has been stopped successfully at ${timestamp}.`); +}); + +// Handle low water level event with timestamp +eventEmitter.on('lowWaterLevel', async (fcmTokens, timestamp) => { + await sendNotification(fcmTokens, 'Low Water Level', `The water level dropped below 20% at ${timestamp}.`); +}); + +// Handle high water level event with timestamp +eventEmitter.on('highWaterLevel', async (fcmTokens, timestamp) => { + await sendNotification(fcmTokens, 'High Water Level', `The water level reached above 90% at ${timestamp}.`); +}); + +// Function to emit events with timestamps +const emitWithTimestamp = (eventName, fcmTokens) => { + const timestamp = moment().format('YYYY-MM-DD HH:mm:ss'); + eventEmitter.emit(eventName, fcmTokens, timestamp); +}; + const sendNotification = async (fcmTokens, title, body) => { if (!Array.isArray(fcmTokens) || fcmTokens.length === 0) { console.error('No FCM tokens provided.'); return; } - const message = { - tokens: fcmTokens, - notification: { - title: title, - body: body, - }, - }; + for (const token of fcmTokens) { + const message = { + token: token, + notification: { + title: title, + body: body, + }, + data: { + target: 'tank_levels', + }, + }; - try { - const response = await admin.messaging().sendMulticast(message); - console.log('Notification sent successfully:', response); - } catch (error) { - console.error('Error sending notification:', error); + try { + const response = await admin.messaging().send(message); // Send each message individually + console.log('Notification sent successfully:', response); + } catch (error) { + console.error(`Failed to send notification to token ${token}:`, error); + } } }; + + // const sendPushNotification = async (registrationToken, title, body) => { // const message = { // notification: { @@ -1372,35 +1426,325 @@ const sendNotification = async (fcmTokens, title, body) => { const stat_stop_intervals = {}; +// exports.motorAction = async (req, reply) => { +// try { +// const customerId = req.params.customerId; +// const action = req.body.action; +// const motorId = req.body.motor_id; +// const start_instance_id = req.body.start_instance_id +// console.log(req.body.startTime) +// // Ensure motor_id is provided +// if (!motorId) { +// throw new Error("Motor ID is required."); +// } + +// const users = await User.find({ customerId: customerId }); +// const fcmToken = users.map(user => user.fcmId).filter(fcmId => fcmId); +// console.log(fcmToken) + +// // Determine the motor stop status based on the action +// let motorStopStatus; +// if (action === "start") { +// motorStopStatus = "2"; // If action is start, set stop status to "2" +// // eventEmitter.emit('motorStart', fcmToken); // Emit motor start event +// emitWithTimestamp('motorStart', fcmToken); // Emit motor start event with timestamp +// console.log( eventEmitter.emit('motorStart', fcmToken)) +// } else if (action === "stop") { +// motorStopStatus = "1"; // If action is stop, set stop status to "1" +// // eventEmitter.emit('motorStop', fcmToken); // Emit motor stop event +// emitWithTimestamp('motorStop', fcmToken); // Emit motor stop event with timestamp +// } else { +// throw new Error("Invalid action provided."); +// } + +// // Update the motor stop status immediately if action is stop +// if (action === "stop") { +// // Update the motor stop status and other fields +// await Tank.updateOne( +// { customerId, "connections.inputConnections.motor_id": motorId }, +// { +// $set: { +// "connections.inputConnections.$.motor_stop_status": "1", +// "connections.inputConnections.$.stopTime": req.body.stopTime, +// "connections.inputConnections.$.threshold_type": null, +// "connections.inputConnections.$.manual_threshold_time": null, +// "connections.inputConnections.$.manual_threshold_percentage": null +// } +// } +// ); + +// reply.code(200).send({ message: "Motor stopped successfully." }); + +// // Perform stop operations in the background +// (async () => { +// await delay(300000); + +// // Update the existing motor data entry with stop details +// const motorData = await MotorData.findOne({ customerId, motor_id: motorId, start_instance_id: start_instance_id }); +// if (motorData) { +// const receiverTank = await Tank.findOne({ customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }); +// const receiverFinalWaterLevel = parseInt(receiverTank.waterlevel, 10); +// const quantityDelivered = receiverFinalWaterLevel - parseInt(motorData.receiverInitialwaterlevel, 10); +// const water_pumped_till_now = parseInt(receiverTank.total_water_added_from_midnight, 10); +// const totalwaterpumped = quantityDelivered + water_pumped_till_now; +// await Tank.findOneAndUpdate( +// { customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }, +// { $set: { total_water_added_from_midnight: totalwaterpumped } } +// ); + +// await MotorData.updateOne( +// { customerId, motor_id: motorId, start_instance_id: start_instance_id }, +// { +// $set: { +// stopTime: req.body.stopTime, +// receiverfinalwaterlevel: receiverFinalWaterLevel.toString(), +// quantity_delivered: quantityDelivered.toString() +// } +// } +// ); + +// } +// })(); + +// // Return here to ensure the rest of the code is not executed for the stop action +// return; +// } else { +// // Update the motor stop status to "2" for start action +// await Tank.updateOne( +// { customerId, "connections.inputConnections.motor_id": motorId }, +// { $set: { "connections.inputConnections.$.motor_stop_status": "2" } } +// ); +// } + +// // Check threshold settings if action is start +// if (action === "start") { +// if (req.body.threshold_type === "time") { +// // If threshold type is time, update threshold time +// // await Tank.updateOne( +// // { customerId, "connections.inputConnections.motor_id": motorId }, +// // { $set: { "connections.inputConnections.$.manual_threshold_time": req.body.manual_threshold_time,startTime:req.body.startTime } } +// // ); +// const receiver_tank_info7 = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); + +// const newMotorData = new MotorData({ +// customerId: customerId, +// motor_id: motorId, +// start_instance_id: start_instance_id, +// supplierTank: req.body.from, +// receiverTank: req.body.to, +// supplier_type: req.body.from_type, +// receiver_type: req.body.to_type, +// startTime: req.body.startTime, +// receiverInitialwaterlevel:parseInt(receiver_tank_info7.waterlevel, 10) +// }); +// await newMotorData.save(); + +// for await (const tank of Tank.find({ "connections.inputConnections.motor_id": motorId })) { +// const index = tank.connections.inputConnections.findIndex(connection => connection.motor_id === motorId); +// if (index !== -1) { +// await Tank.updateOne( +// { customerId, "connections.inputConnections.motor_id": motorId }, +// { $set: { [`connections.inputConnections.${index}.manual_threshold_time`]: req.body.manual_threshold_time, [`connections.inputConnections.${index}.startTime`]: req.body.startTime,[`connections.inputConnections.${index}.start_instance_id`]: start_instance_id } } +// ); +// } +// } + + +// // Start monitoring water level based on threshold time +// const thresholdTime = moment().add(req.body.manual_threshold_time, 'minutes').toDate(); +// const intervalId = setInterval(async () => { +// const splr_tank_info3 = await Tank.findOne({ customerId, tankName: req.body.from, tankLocation: req.body.from_type.toLowerCase() }); +// const splr_tank_info3_waterlevel = parseInt(splr_tank_info3.waterlevel, 10); +// //console.log(splr_tank_info3_waterlevel,"splr_tank_info3_waterlevel") +// const splr_tank_info3_capacity = parseInt(splr_tank_info3.capacity.replace(/,/g, ''), 10); +// // const splr_tank_info3_capacity = parseInt(splr_tank_info3.capacity, 10); +// // console.log(splr_tank_info3.capacity,splr_tank_info3_capacity,"splr_tank_info3_capacity") +// const splr_tank_info3_percentage = (splr_tank_info3_waterlevel / splr_tank_info3_capacity) * 100; +// // console.log(splr_tank_info3_percentage, "percentage for less than 20"); + +// if (new Date() >= thresholdTime || splr_tank_info3_percentage <= 20) { +// console.log(splr_tank_info3_percentage,) +// await Tank.updateOne( +// { customerId, "connections.inputConnections.motor_id": motorId }, +// { +// $set: { +// "connections.inputConnections.$.motor_stop_status": "1", +// "connections.inputConnections.$.threshold_type": null, +// "connections.inputConnections.$.manual_threshold_time": null, +// "connections.inputConnections.$.manual_threshold_percentage": null +// } +// } +// ); +// clearInterval(intervalId); + +// await delay(300000); + +// const motorData = await MotorData.findOne({ customerId, motor_id: motorId, start_instance_id: start_instance_id }); +// if (motorData) { +// const receiverTank = await Tank.findOne({ customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }); +// const receiverFinalWaterLevel = parseInt(receiverTank.waterlevel, 10); +// const quantityDelivered = receiverFinalWaterLevel - parseInt(motorData.receiverInitialwaterlevel, 10); +// const water_pumped_till_now = parseInt(receiverTank.total_water_added_from_midnight, 10); +// const totalwaterpumped = quantityDelivered + water_pumped_till_now +// await Tank.findOneAndUpdate({customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase()}, { $set: { total_water_added_from_midnight: totalwaterpumped } }) + +// const stopTime = formatDate(new Date()); + +// await MotorData.updateOne( +// { customerId, motor_id: motorId, start_instance_id: start_instance_id }, +// { +// $set: { +// stopTime:stopTime, +// receiverfinalwaterlevel: receiverFinalWaterLevel.toString(), +// quantity_delivered: quantityDelivered.toString() +// } +// } +// ); +// } +// } +// }, 60000); +// } else if (req.body.threshold_type === "litres") { +// console.log("entered litres") +// const receiver_tank_info7 = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); + +// const newMotorData = new MotorData({ +// customerId: customerId, +// motor_id: motorId, +// start_instance_id: start_instance_id, +// supplierTank: req.body.from, +// receiverTank: req.body.to, +// supplier_type: req.body.from_type, +// receiver_type: req.body.to_type, +// startTime: req.body.startTime, +// receiverInitialwaterlevel:parseInt(receiver_tank_info7.waterlevel, 10) +// }); +// await newMotorData.save(); +// // If threshold type is percentage, calculate percentage threshold +// const receiver_tank_info = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); +// const supplier_tank_info = await Tank.findOne({ customerId, tankName: req.body.from, tankLocation: req.body.from_type.toLowerCase() }); +// if (!receiver_tank_info) { +// throw new Error("Receiver tank not found."); +// } +// if (!supplier_tank_info) { +// throw new Error("Supplierr tank not found."); +// } +// const supplier_capacity = parseInt(supplier_tank_info.capacity, 10); +// const supplier_waterLevel = parseInt(supplier_tank_info.waterlevel, 10); + +// const capacity = parseInt(receiver_tank_info.capacity, 10); +// const waterLevel = parseInt(receiver_tank_info.waterlevel, 10); +// const desired_percentage = parseInt(req.body.manual_threshold_litres.replace(/,/g, ''), 10); + +// console.log(desired_percentage) +// const threshold_water_level = waterLevel+desired_percentage; + +// const supplier_threshold = supplier_waterLevel-desired_percentage +// console.log(supplier_threshold,"supplier_threshold") + +// for await (const tank of Tank.find({ "connections.inputConnections.motor_id": motorId })) { +// const index = tank.connections.inputConnections.findIndex(connection => connection.motor_id === motorId); +// if (index !== -1) { +// await Tank.updateOne( +// { customerId, "connections.inputConnections.motor_id": motorId }, +// { $set: { [`connections.inputConnections.${index}.manual_threshold_percentage`]: supplier_threshold.toString(), [`connections.inputConnections.${index}.startTime`]: req.body.startTime } } +// ); +// } +// } + + + +// // Update water level threshold + + +// // Start monitoring water level based on threshold percentage +// const intervalId = setInterval(async () => { +// // Check if water level has reached the threshold percentage +// const supplier_tank_info1 = await Tank.findOne({ customerId, tankName: req.body.from, tankLocation: req.body.from_type.toLowerCase() }); +// const current_water_level = parseInt(supplier_tank_info1.waterlevel, 10); +// if (current_water_level <= supplier_threshold) { +// // Stop the motor pump +// await Tank.updateOne( +// { customerId, "connections.inputConnections.motor_id": motorId }, +// { +// $set: { +// "connections.inputConnections.$.motor_stop_status": "1", + +// "connections.inputConnections.$.threshold_type": null, +// "connections.inputConnections.$.manual_threshold_time": null, +// "connections.inputConnections.$.manual_threshold_percentage": null +// } +// } +// ); +// clearInterval(intervalId); // Stop monitoring water level +// await delay(300000); + +// const motorData = await MotorData.findOne({ customerId, motor_id: motorId, start_instance_id: start_instance_id }); +// if (motorData) { +// const receiverTank = await Tank.findOne({ customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }); +// const receiverFinalWaterLevel = parseInt(receiverTank.waterlevel, 10); +// const quantityDelivered = receiverFinalWaterLevel - parseInt(motorData.receiverInitialwaterlevel, 10); + + +// const stopTime = formatDate(new Date()); + +// await MotorData.updateOne( +// { customerId, motor_id: motorId, start_instance_id: start_instance_id }, +// { +// $set: { +// stopTime:stopTime, +// receiverfinalwaterlevel: receiverFinalWaterLevel.toString(), +// quantity_delivered: quantityDelivered.toString() +// } +// } +// ); +// } +// } +// }, 20000); // Check water level every minute +// } +// } + +// // Respond with success message +// reply.code(200).send({ message: `Motor ${action === "start" ? "started" : "stopped"} successfully.` }); +// } catch (err) { +// // Handle errors +// throw boom.boomify(err); +// } +// }; + exports.motorAction = async (req, reply) => { try { const customerId = req.params.customerId; const action = req.body.action; const motorId = req.body.motor_id; - const start_instance_id = req.body.start_instance_id - console.log(req.body.startTime) + const start_instance_id = req.body.start_instance_id; + + // Define thresholds for water levels + const lowWaterThreshold = 20; // Low water level percentage threshold + const highWaterThreshold = 90; // High water level percentage threshold + // Ensure motor_id is provided if (!motorId) { throw new Error("Motor ID is required."); } - const users = await User.find({ customerId: customerId }); + // Get user FCM tokens + const users = await User.find({ customerId }); const fcmToken = users.map(user => user.fcmId).filter(fcmId => fcmId); - console.log(fcmToken) // Determine the motor stop status based on the action let motorStopStatus; if (action === "start") { motorStopStatus = "2"; // If action is start, set stop status to "2" + emitWithTimestamp('motorStart', fcmToken); // Emit motor start notification with timestamp } else if (action === "stop") { motorStopStatus = "1"; // If action is stop, set stop status to "1" + emitWithTimestamp('motorStop', fcmToken); // Emit motor stop notification with timestamp } else { throw new Error("Invalid action provided."); } - // Update the motor stop status immediately if action is stop + // If action is stop, immediately update motor status and perform stop operations if (action === "stop") { - // Update the motor stop status and other fields await Tank.updateOne( { customerId, "connections.inputConnections.motor_id": motorId }, { @@ -1414,14 +1758,12 @@ exports.motorAction = async (req, reply) => { } ); - // Send immediate response to the client reply.code(200).send({ message: "Motor stopped successfully." }); // Perform stop operations in the background (async () => { await delay(300000); - // Update the existing motor data entry with stop details const motorData = await MotorData.findOne({ customerId, motor_id: motorId, start_instance_id: start_instance_id }); if (motorData) { const receiverTank = await Tank.findOne({ customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }); @@ -1429,6 +1771,7 @@ exports.motorAction = async (req, reply) => { const quantityDelivered = receiverFinalWaterLevel - parseInt(motorData.receiverInitialwaterlevel, 10); const water_pumped_till_now = parseInt(receiverTank.total_water_added_from_midnight, 10); const totalwaterpumped = quantityDelivered + water_pumped_till_now; + await Tank.findOneAndUpdate( { customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }, { $set: { total_water_added_from_midnight: totalwaterpumped } } @@ -1444,14 +1787,11 @@ exports.motorAction = async (req, reply) => { } } ); - } })(); - // Return here to ensure the rest of the code is not executed for the stop action - return; + return; // Return early to avoid executing the start logic } else { - // Update the motor stop status to "2" for start action await Tank.updateOne( { customerId, "connections.inputConnections.motor_id": motorId }, { $set: { "connections.inputConnections.$.motor_stop_status": "2" } } @@ -1461,15 +1801,10 @@ exports.motorAction = async (req, reply) => { // Check threshold settings if action is start if (action === "start") { if (req.body.threshold_type === "time") { - // If threshold type is time, update threshold time - // await Tank.updateOne( - // { customerId, "connections.inputConnections.motor_id": motorId }, - // { $set: { "connections.inputConnections.$.manual_threshold_time": req.body.manual_threshold_time,startTime:req.body.startTime } } - // ); - const receiver_tank_info7 = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); - + // Create a new MotorData entry + const receiverTank = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); const newMotorData = new MotorData({ - customerId: customerId, + customerId, motor_id: motorId, start_instance_id: start_instance_id, supplierTank: req.body.from, @@ -1477,38 +1812,37 @@ exports.motorAction = async (req, reply) => { supplier_type: req.body.from_type, receiver_type: req.body.to_type, startTime: req.body.startTime, - receiverInitialwaterlevel:parseInt(receiver_tank_info7.waterlevel, 10) + receiverInitialwaterlevel: parseInt(receiverTank.waterlevel, 10) }); await newMotorData.save(); - for await (const tank of Tank.find({ "connections.inputConnections.motor_id": motorId })) { + // Update the tank connections with start time and threshold time + for await (const tank of Tank.find({ "connections.inputConnections.motor_id": motorId })) { const index = tank.connections.inputConnections.findIndex(connection => connection.motor_id === motorId); if (index !== -1) { await Tank.updateOne( { customerId, "connections.inputConnections.motor_id": motorId }, - { $set: { [`connections.inputConnections.${index}.manual_threshold_time`]: req.body.manual_threshold_time, [`connections.inputConnections.${index}.startTime`]: req.body.startTime,[`connections.inputConnections.${index}.start_instance_id`]: start_instance_id } } + { + $set: { + [`connections.inputConnections.${index}.manual_threshold_time`]: req.body.manual_threshold_time, + [`connections.inputConnections.${index}.startTime`]: req.body.startTime, + [`connections.inputConnections.${index}.start_instance_id`]: start_instance_id + } + } ); } } - - // Start monitoring water level based on threshold time const thresholdTime = moment().add(req.body.manual_threshold_time, 'minutes').toDate(); const intervalId = setInterval(async () => { - const splr_tank_info3 = await Tank.findOne({ customerId, tankName: req.body.from, tankLocation: req.body.from_type.toLowerCase() }); - const splr_tank_info3_waterlevel = parseInt(splr_tank_info3.waterlevel, 10); - //console.log(splr_tank_info3_waterlevel,"splr_tank_info3_waterlevel") - const splr_tank_info3_capacity = parseInt(splr_tank_info3.capacity.replace(/,/g, ''), 10); - // const splr_tank_info3_capacity = parseInt(splr_tank_info3.capacity, 10); - // console.log(splr_tank_info3.capacity,splr_tank_info3_capacity,"splr_tank_info3_capacity") - const splr_tank_info3_percentage = (splr_tank_info3_waterlevel / splr_tank_info3_capacity) * 100; - // console.log(splr_tank_info3_percentage, "percentage for less than 20"); - - if (new Date() >= thresholdTime || splr_tank_info3_percentage <= 20) { - console.log(splr_tank_info3_percentage,) + const supplierTank = await Tank.findOne({ customerId, tankName: req.body.from, tankLocation: req.body.from_type.toLowerCase() }); + const currentWaterLevel = parseInt(supplierTank.waterlevel, 10); + const currentWaterPercentage = (currentWaterLevel / parseInt(supplierTank.capacity.replace(/,/g, ''), 10)) * 100; + + if (new Date() >= thresholdTime || currentWaterPercentage <= lowWaterThreshold) { await Tank.updateOne( { customerId, "connections.inputConnections.motor_id": motorId }, - { + { $set: { "connections.inputConnections.$.motor_stop_status": "1", "connections.inputConnections.$.threshold_type": null, @@ -1517,26 +1851,28 @@ exports.motorAction = async (req, reply) => { } } ); + emitWithTimestamp('lowWaterLevel', fcmToken); // Emit low water level notification clearInterval(intervalId); await delay(300000); - const motorData = await MotorData.findOne({ customerId, motor_id: motorId, start_instance_id: start_instance_id }); if (motorData) { const receiverTank = await Tank.findOne({ customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }); const receiverFinalWaterLevel = parseInt(receiverTank.waterlevel, 10); const quantityDelivered = receiverFinalWaterLevel - parseInt(motorData.receiverInitialwaterlevel, 10); const water_pumped_till_now = parseInt(receiverTank.total_water_added_from_midnight, 10); - const totalwaterpumped = quantityDelivered + water_pumped_till_now - await Tank.findOneAndUpdate({customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase()}, { $set: { total_water_added_from_midnight: totalwaterpumped } }) + const totalwaterpumped = quantityDelivered + water_pumped_till_now; - const stopTime = formatDate(new Date()); + await Tank.findOneAndUpdate( + { customerId, tankName: motorData.receiverTank, tankLocation: motorData.receiver_type.toLowerCase() }, + { $set: { total_water_added_from_midnight: totalwaterpumped } } + ); await MotorData.updateOne( { customerId, motor_id: motorId, start_instance_id: start_instance_id }, { $set: { - stopTime:stopTime, + stopTime: req.body.stopTime, receiverfinalwaterlevel: receiverFinalWaterLevel.toString(), quantity_delivered: quantityDelivered.toString() } @@ -1544,7 +1880,14 @@ exports.motorAction = async (req, reply) => { ); } } - }, 60000); + + // Check for high water level and send notification + if (currentWaterPercentage >= highWaterThreshold) { + emitWithTimestamp('highWaterLevel', fcmToken); // Emit high water level notification + } + + }, 60000); // Check every minute + } else if (req.body.threshold_type === "litres") { console.log("entered litres") const receiver_tank_info7 = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); @@ -1641,14 +1984,14 @@ exports.motorAction = async (req, reply) => { ); } } - }, 20000); // Check water level every minute + }, 20000); } } // Respond with success message reply.code(200).send({ message: `Motor ${action === "start" ? "started" : "stopped"} successfully.` }); + } catch (err) { - // Handle errors throw boom.boomify(err); } }; From c12635d76f0f35f0b635edbda38b31dfd83d2b1f Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Mon, 14 Oct 2024 11:33:07 +0530 Subject: [PATCH 3/7] changes --- src/controllers/tanksController.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index 52b066b1..0e8b3d5e 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -1902,7 +1902,7 @@ exports.motorAction = async (req, reply) => { } }, 60000); // Check every minute - + } } else if (req.body.threshold_type === "litres") { console.log("entered litres") const receiver_tank_info7 = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); @@ -2002,7 +2002,6 @@ exports.motorAction = async (req, reply) => { }, 20000); } } - // Respond with success message reply.code(200).send({ message: `Motor ${action === "start" ? "started" : "stopped"} successfully.` }); From 5c3658fec6ca51b991057f031de27788e4097b28 Mon Sep 17 00:00:00 2001 From: Bhaskar Date: Wed, 16 Oct 2024 12:04:34 +0530 Subject: [PATCH 4/7] chnages on notification --- src/controllers/tanksController.js | 40 +++++++++++++++++------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index 0e8b3d5e..aff63e2b 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -1342,31 +1342,33 @@ admin.initializeApp({ // }); // Handle motor start event with timestamp -eventEmitter.on('motorStart', async (fcmTokens, timestamp) => { - await sendNotification(fcmTokens, 'Motor Started', `The motor has been started successfully at ${timestamp}.`); +eventEmitter.on('motorStart', async (fcmTokens, timestamp, motorId, waterLevel) => { + await sendNotification(fcmTokens, 'Motor Started', `Motor ID: ${motorId} started successfully at ${timestamp}. Current Water Level: ${waterLevel} Ltrs`); }); -// Handle motor stop event with timestamp -eventEmitter.on('motorStop', async (fcmTokens, timestamp) => { - await sendNotification(fcmTokens, 'Motor Stopped', `The motor has been stopped successfully at ${timestamp}.`); +// Emit motor stop event with motorId +eventEmitter.on('motorStop', async (fcmTokens, timestamp, motorId, waterLevel) => { + await sendNotification(fcmTokens, 'Motor Stopped', `Motor ID: ${motorId} stopped successfully at ${timestamp}.Current Water Level: ${waterLevel} Ltrs`); }); -// Handle low water level event with timestamp -eventEmitter.on('lowWaterLevel', async (fcmTokens, timestamp) => { - await sendNotification(fcmTokens, 'Low Water Level', `The water level dropped below 20% at ${timestamp}.`); +// Emit low water level event with motorId +eventEmitter.on('lowWaterLevel', async (fcmTokens, timestamp, motorId, waterLevel) => { + await sendNotification(fcmTokens, 'Low Water Level', `Motor ID: ${motorId}, water level dropped below 20% at ${timestamp}. Current Water Level: ${waterLevel} Ltrs`); }); -// Handle high water level event with timestamp -eventEmitter.on('highWaterLevel', async (fcmTokens, timestamp) => { - await sendNotification(fcmTokens, 'High Water Level', `The water level reached above 90% at ${timestamp}.`); +// Emit high water level event with motorId +eventEmitter.on('highWaterLevel', async (fcmTokens, timestamp, motorId, waterLevel) => { + await sendNotification(fcmTokens, 'High Water Level', `Motor ID: ${motorId}, water level reached above 90% at ${timestamp}. Current Water Level: ${waterLevel} Ltrs`); }); + // Function to emit events with timestamps -const emitWithTimestamp = (eventName, fcmTokens) => { - const timestamp = moment().format('YYYY-MM-DD HH:mm:ss'); - eventEmitter.emit(eventName, fcmTokens, timestamp); +const emitWithTimestamp = (eventName, fcmTokens, motorId, waterLevel) => { + const timestamp = moment().format('HH:mm:ss YYYY-MM-DD '); + eventEmitter.emit(eventName, fcmTokens, timestamp, motorId, waterLevel); }; + const sendNotification = async (fcmTokens, title, body) => { if (!Array.isArray(fcmTokens) || fcmTokens.length === 0) { console.error('No FCM tokens provided.'); @@ -1742,14 +1744,18 @@ exports.motorAction = async (req, reply) => { const users = await User.find({ customerId }); const fcmToken = users.map(user => user.fcmId).filter(fcmId => fcmId); + const receiverTank = await Tank.findOne({ customerId, tankName: req.body.to, tankLocation: req.body.to_type.toLowerCase() }); + console.log(receiverTank) + const currentWaterLevel = parseInt(receiverTank.waterlevel, 10); + // Determine the motor stop status based on the action let motorStopStatus; if (action === "start") { motorStopStatus = "2"; // If action is start, set stop status to "2" - emitWithTimestamp('motorStart', fcmToken); // Emit motor start notification with timestamp + emitWithTimestamp('motorStart', fcmToken, motorId, currentWaterLevel); } else if (action === "stop") { motorStopStatus = "1"; // If action is stop, set stop status to "1" - emitWithTimestamp('motorStop', fcmToken); // Emit motor stop notification with timestamp + emitWithTimestamp('motorStop', fcmToken, motorId, currentWaterLevel); } else { throw new Error("Invalid action provided."); } @@ -4270,7 +4276,7 @@ exports.getBlockData = async (req, reply) => { const mqtt = require('mqtt'); -const client = mqtt.connect('mqtt://35.207.198.4:1883'); // Connect to MQTT broker +const client = mqtt.connect('mqtt://35.207.198.4:1884'); // Connect to MQTT broker client.on('connect', () => { console.log('Connected to MQTT broker'); From b0558c1ecba9e12c0bc4ff3cf3baad77ab66184a Mon Sep 17 00:00:00 2001 From: Naidu Date: Tue, 15 Oct 2024 23:49:53 -0700 Subject: [PATCH 5/7] Admin, sales & store changes --- src/controllers/admincontroller.js | 244 ++++------------------------- src/models/admin.js | 2 +- src/routes/adminRoute.js | 24 --- 3 files changed, 32 insertions(+), 238 deletions(-) diff --git a/src/controllers/admincontroller.js b/src/controllers/admincontroller.js index c389ef56..fedd079c 100644 --- a/src/controllers/admincontroller.js +++ b/src/controllers/admincontroller.js @@ -8,14 +8,30 @@ const fastify = require("fastify"); const { Tank, MotorData, IotData } = require('../models/tanks') const JWT_SECRET = 'your-secret-key'; -async function generateCustomerId() { +async function generateCustomerId(role) { let customerId; let isUnique = false; + let prefix; + + // Set the prefix based on the role + switch (role) { + case 'admin': + prefix = 'AWSAD'; + break; + case 'sales': + prefix = 'AWSSL'; + break; + case 'store': + prefix = 'AWSST'; + break; + default: + throw new Error('Invalid role for customer ID generation'); + } while (!isUnique) { // Generate a random number or string for the customer ID - customerId = Math.floor(1000 + Math.random() * 9000).toString(); // Generates a random number between 1000 and 9999 - + const randomId = Math.floor(1000 + Math.random() * 9000).toString(); // Generates a random number between 1000 and 9999 + customerId = `${prefix}${randomId}`; // Check for uniqueness in the Admin collection const existingAdmin = await Admin.findOne({ customerId }); if (!existingAdmin) { @@ -26,146 +42,6 @@ async function generateCustomerId() { return customerId; } -// exports.adminSignUp = async (request, reply) => { - -// try { -// const { email, password } = request.body - -// // Check if an admin with the same email address already exists -// const existingAdmin = await Admin.findOne({ email }) - -// if (existingAdmin) { -// return reply.status(400).send({ message: 'Email already registered' }) -// } - -// // Hash the password using bcrypt -// const hashedPassword = await bcrypt.hash(password, 10) - -// // Create a new admin object with the hashed password -// const admin = new Admin({ email, password: hashedPassword }) - -// // Save the new admin to the database -// await admin.save() - -// // Generate a JWT token for the new admin -// // const token = jwt.sign({ email: admin.email }, 'secret') - -// // // Return the token to the client -// // return { token } -// reply.send({message : "Admin Account Created Sucessfully"}) -// } catch (err) { -// reply.status(500).send({ message: err.message }) -// } -// } - -// exports.adminSignUp = async (request, reply) => { - -// try { -// const { email, password } = request.body - -// // Check if the email address is valid -// const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ -// if (!emailRegex.test(email)) { -// return reply.status(400).send({ message: 'Invalid email address' }) -// } - -// // Check if an admin with the same email address already exists -// const existingAdmin = await Admin.findOne({ email }) - -// if (existingAdmin) { -// return reply.status(400).send({ message: 'Email already registered' }) -// } - -// // Hash the password using bcrypt -// const hashedPassword = await bcrypt.hash(password, 10) - -// // Create a new admin object with the hashed password -// const admin = new Admin({ email, password: hashedPassword }) - -// // Save the new admin to the database -// await admin.save() - -// // Generate a JWT token for the new admin -// // const token = jwt.sign({ email: admin.email }, 'secret') - -// // // Return the token to the client -// // return { token } -// reply.send({message : "Admin Account Created Sucessfully"}) -// } catch (err) { -// reply.status(500).send({ message: err.message }) -// } -// } - - - -// exports.adminLogin = async (request, reply) => { -// try { -// const { email, password } = request.body - -// // Check if an admin with the email address exists -// const admin = await Admin.findOne({ email }) - -// if (!admin) { -// return reply.status(401).send({ message: 'Invalid email or password' }) -// } - -// // Compare the password entered by the user with the hashed password stored in the database -// const isPasswordValid = await bcrypt.compare(password, admin.password) - -// if (!isPasswordValid) { -// return reply.status(401).send({ message: 'Invalid email or password' }) -// } - -// // Generate a JWT token for the authenticated admin -// const token = jwt.sign({ email: admin.email }, 'secret') - -// // Return the token to the client -// return { token } -// } catch (err) { -// reply.status(500).send({ message: err.message }) -// } -// } - - -// Admin Sign-Up Function -// exports.adminSignUp = async (request, reply) => { -// try { -// const { phone,username, password } = request.body; - -// // Check if the email address is valid -// // const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; -// // if (!emailRegex.test(email)) { -// // return reply.status(400).send({ message: 'Invalid email address' }); -// // } -// if (!username || username.trim() === '') { -// return reply.status(400).send({ message: 'Username is required' }); -// } - - -// // Check if an admin with the same email address already exists -// const existingAdminUsername = await Admin.findOne({ username }); -// const existingAdmin = await Admin.findOne({ phone }); -// if (existingAdmin) { -// return reply.status(400).send({ message: 'phone already registered' }); -// } -// if (existingAdminUsername) { -// return reply.status(400).send({ message: 'Username already registered' }); -// } - -// // Hash the password using bcrypt -// const hashedPassword = await bcrypt.hash(password, 10); - -// // Create a new admin object with the hashed password -// const admin = new Admin({ phone,username, password: hashedPassword }); - -// // Save the new admin to the database -// await admin.save(); - -// reply.send({ message: 'Admin Account Created Successfully' }); -// } catch (err) { -// reply.status(500).send({ message: err.message }); -// } -// }; exports.adminSignUp = async (request, reply) => { try { @@ -176,29 +52,29 @@ exports.adminSignUp = async (request, reply) => { } // Validate role - if (!['admin', 'sales', 'store'].includes(role)) { + if (!role || !['admin', 'sales', 'store'].includes(role)) { return reply.status(400).send({ message: 'Invalid role. Must be either admin, sales, or store' }); } // Check if an admin with the same phone number or username already exists - const existingAdminUsername = await Admin.findOne({ username }); - const existingAdmin = await Admin.findOne({ phone }); + // const existingAdminUsername = await Admin.findOne({ username }); + // const existingAdmin = await Admin.findOne({ phone }); - if (existingAdmin) { - return reply.status(400).send({ message: 'Phone already registered' }); - } - if (existingAdminUsername) { - return reply.status(400).send({ message: 'Username already registered' }); - } + // if (existingAdmin) { + // return reply.status(400).send({ message: 'Phone already registered' }); + // } + // if (existingAdminUsername) { + // return reply.status(400).send({ message: 'Username already registered' }); + // } // Hash the password using bcrypt const hashedPassword = await bcrypt.hash(password, 10); - const c_id = await generateCustomerId(); // Assuming you have this function defined elsewhere - const building = 'ADMIN'; // You can customize this logic to derive from a parameter or a default value - const customerId = `AWSU${building}${c_id}`; // Construct the customer ID + const customerId = await generateCustomerId(role); // Assuming you have this function defined elsewhere + //const building = 'ADMIN'; // You can customize this logic to derive from a parameter or a default value + //const customerId = `AWSU${building}${c_id}`; // Construct the customer ID // Create a new admin object with the hashed password and role const admin = new Admin({ phone, username, password: hashedPassword, customerId, role }); @@ -241,33 +117,7 @@ exports.adminLogin = async (request, reply) => { } }; -// Sales and Store Login (Phone and Password) -// exports.salesStoreLogin = async (request, reply) => { -// try { -// const { phone, password } = request.body; - -// // Check if a user (sales or store) with the phone number exists -// const admin = await Admin.findOne({ phone }); - -// if (!admin) { -// return reply.status(401).send({ message: 'Invalid phone number or password' }); -// } - -// // Compare the password entered by the user with the hashed password stored in the database -// const isPasswordValid = await bcrypt.compare(password, admin.password); - -// if (!isPasswordValid) { -// return reply.status(401).send({ message: 'Invalid phone number or password' }); -// } -// // Generate a JWT token for the authenticated user (with role sales or store) -// const token = jwt.sign({ phone: admin.phone, role: admin.role }, JWT_SECRET, { expiresIn: '1h' }); - -// return reply.send({ token }); -// } catch (err) { -// reply.status(500).send({ message: err.message }); -// } -// }; exports.salesStoreLogin = async (request, reply) => { try { @@ -341,39 +191,7 @@ exports.getUserByCustomerId = async (request, reply) => { }; -// Create Sales/Store User (Admin Only) -// exports.createUser = async (request, reply) => { -// const { phone, password, role } = request.body; - -// // Validate role (only sales or store) -// if (!['sales', 'store'].includes(role)) { -// return reply.status(400).send({ message: 'Invalid role. Must be either sales or store' }); -// } - -// try { -// const existingUser = await Admin.findOne({ phone }); - -// if (existingUser) { -// return reply.status(400).send({ message: 'User with this phone number already exists' }); -// } - -// // Hash the password -// const hashedPassword = await bcrypt.hash(password, 10); - -// // Create the new user -// const newUser = new Admin({ -// phone, -// password: hashedPassword, -// role, -// }); - -// await newUser.save(); -// return reply.send({ message: 'User created successfully' }); -// } catch (err) { -// reply.status(500).send({ message: err.message }); -// } -// }; exports.createUser = async (request, reply) => { const { phone, password, role } = request.body; diff --git a/src/models/admin.js b/src/models/admin.js index 2a962f4c..c386110a 100644 --- a/src/models/admin.js +++ b/src/models/admin.js @@ -13,7 +13,7 @@ const adminSchema = new mongoose.Schema({ username: { type: String, required: true, - unique: true, + // unique: true, }, password: { type: String, diff --git a/src/routes/adminRoute.js b/src/routes/adminRoute.js index 54629f06..997cffde 100644 --- a/src/routes/adminRoute.js +++ b/src/routes/adminRoute.js @@ -3,31 +3,7 @@ const adminController = require('../controllers/admincontroller') module.exports = function (fastify, opts, next) { -// fastify.route({ -// method: "POST", -// url: "/api/adminSignup", -// schema: { -// tags: ["Admin"], -// description: "This is for cretae New Admin Account", -// summary: "This is for cretae New Admin Account", -// body: { -// type: "object", -// properties: { -// phone : { type: "string" }, -// password: { type: "string" }, -// username:{type:"string"}, -// }, -// }, -// security: [ -// { -// basicAuth: [], -// }, -// ], -// }, -// handler: adminController.adminSignUp, - -// }); fastify.route({ method: "POST", From 92c9f08c37d1bf944356156bb5aeb1b185877d96 Mon Sep 17 00:00:00 2001 From: Varun Date: Wed, 16 Oct 2024 14:05:41 +0530 Subject: [PATCH 6/7] consumptions of particular tank --- src/controllers/tanksController.js | 69 ++++++++++++++++++++++++++++++ src/routes/tanksRoute.js | 37 ++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index aff63e2b..b52a17fd 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -4408,5 +4408,74 @@ client.on('message', async (topic, message) => { // }; +exports.consumptionofparticulartank = async (request, reply) => { + try { + const { customerId } = request.params; + const { startDate, stopDate, tankName, tankLocation, block } = request.body; + + // Ensure dates are formatted or parsed correctly for the query + const start = startDate; + const end = stopDate; + + // Find the tank by customerId, tankLocation, and tankName + const tank = await Tank.findOne({ + customerId, + tankLocation: tankLocation || "overhead", // Default to "overhead" if not provided + tankName, + }); + + if (!tank) { + return reply.status(404).send({ + status_code: 404, + message: "Tank not found", + }); + } + + const waterlevel_at_midnight = parseInt(tank.waterlevel_at_midnight.replace(/,/g, ""), 10); + const total_water_added_from_midnight = parseInt(tank.total_water_added_from_midnight.replace(/,/g, ""), 10); + const waterlevel = parseInt(tank.waterlevel.replace(/,/g, ""), 10); + + // Find consumption records for the tank between the given dates + const tankConsumptions = await TankConsumptionOriginalSchema.find({ + customerId, + tankName, + tankLocation: tankLocation, + time: { + $gte: start, + $lte: end, + }, + + }); + + // Calculate total consumption from records + const total_consumption_from_records = tankConsumptions.reduce((acc, record) => { + return acc + parseInt(record.consumption, 10); + }, 0); + + // Calculate final consumption + const consumption = (waterlevel_at_midnight + total_water_added_from_midnight) - waterlevel + total_consumption_from_records; + + // Prepare response data + const tankData = { + tankname: tank.tankName, + totalConsumption: consumption, + block: tank.blockName, + TypeofWater: tank.typeOfWater, + location: tank.tankLocation, + capacity: tank.capacity, + waterlevel: tank.waterlevel, + }; + + // Send the response, including both total consumption and tankConsumptions data + reply.send({ + status_code: 200, + tankData, + totalConsumption: consumption, + consumptionRecords: tankConsumptions, // Add the consumption records here + }); + } catch (err) { + throw boom.boomify(err); + } +}; diff --git a/src/routes/tanksRoute.js b/src/routes/tanksRoute.js index 4aebc5fe..fdb84428 100644 --- a/src/routes/tanksRoute.js +++ b/src/routes/tanksRoute.js @@ -1001,6 +1001,43 @@ module.exports = function (fastify, opts, next) { handler: tanksController.getBlockData, }); + fastify.route({ + method: "PUT", + url: "/api/consumptionofparticulartank/:customerId", + schema: { + tags: ["Tank"], + summary: "This is for getting consumption of a particular tank", + params: { + required: ["customerId"], + type: "object", + properties: { + customerId: { + type: "string", + description: "Customer ID", + }, + }, + }, + body: { + type: "object", + properties: { + tankName: { type: "string", description: "Tank name" }, + tankLocation: { type: "string", description: "Tank location" }, + startDate: { type: "string", description: "Start date" }, + stopDate: { type: "string", description: "Stop date" }, + block: { type: "string", description: "Block name" }, + }, + }, + security: [ + { + basicAuth: [], + }, + ], + }, + // preHandler: fastify.auth([fastify.authenticate]), + handler: tanksController.consumptionofparticulartank, + }); + + next(); } From 22625f9d921fce1f88d5e7bc6c28ca761f1578d2 Mon Sep 17 00:00:00 2001 From: Varun Date: Wed, 16 Oct 2024 14:12:27 +0530 Subject: [PATCH 7/7] change in saving conxumption at midnight --- src/controllers/tanksController.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/tanksController.js b/src/controllers/tanksController.js index b52a17fd..894841db 100644 --- a/src/controllers/tanksController.js +++ b/src/controllers/tanksController.js @@ -3791,7 +3791,7 @@ const updatetotalConsumptiontillmidnight = async () => { const formattedDate = moment().tz('Asia/Kolkata').format('DD-MMM-YYYY - HH:mm'); // Check if the record already exists - const existingRecord = await TankConsumptionSchema.findOne({ + const existingRecord = await TankConsumptionOriginalSchema.findOne({ customerId: tank.customerId, tankName: tank.tankName, tankLocation: tank.tankLocation, @@ -3800,7 +3800,7 @@ const updatetotalConsumptiontillmidnight = async () => { if (!existingRecord) { // Create and save the new document if it doesn't exist - const newTankConsumption = new TankConsumptionSchema({ + const newTankConsumption = new TankConsumptionOriginalSchema({ customerId: tank.customerId, tankName: tank.tankName, tankLocation: tank.tankLocation, @@ -3826,7 +3826,7 @@ const updatetotalConsumptiontillmidnight = async () => { clearConsumptionSchedule(); // Schedule the task to run every day at 12:49 PM IST and store the reference -consumptionTask = cron.schedule('32 15 * * *', updatetotalConsumptiontillmidnight, { +consumptionTask = cron.schedule('50 23 * * *', updatetotalConsumptiontillmidnight, { timezone: "Asia/Kolkata" });