From b45b05f033a548a37c39fac7b605d21216d1e927 Mon Sep 17 00:00:00 2001 From: Douglas Barone Date: Wed, 15 Jun 2022 11:35:20 +0000 Subject: [PATCH] Basic stats working --- server/src/cronTasks.js | 2 +- server/src/lib/ciscoController.js | 2 +- server/src/lib/unifiController.js | 2 +- server/src/lib/wifiStats.js | 4 +- server/src/resolvers/AccessPoint.js | 14 +- server/src/resolvers/WifiStats.js | 1 + web/package-lock.json | 27 ++++ web/package.json | 2 + .../Charts/AccessPointClientsChart.vue | 108 +++++++++++++++ .../Charts/AccessPointSignalStrengthChart.vue | 130 ++++++++++++++++++ web/src/views/AccessPoints/clients.vue | 34 ++++- 11 files changed, 317 insertions(+), 9 deletions(-) create mode 100644 web/src/components/Charts/AccessPointClientsChart.vue create mode 100644 web/src/components/Charts/AccessPointSignalStrengthChart.vue diff --git a/server/src/cronTasks.js b/server/src/cronTasks.js index 78455d0..1b76671 100644 --- a/server/src/cronTasks.js +++ b/server/src/cronTasks.js @@ -46,7 +46,7 @@ cron.schedule('0 */2 * * * *', () => { updateAccessPoints().catch(console.log) }) -cron.schedule('0 */5 * * * *', () => { +cron.schedule('0 */1 * * * *', () => { generateStatsForAllAccessPoints() }) diff --git a/server/src/lib/ciscoController.js b/server/src/lib/ciscoController.js index 75a07e0..27fefb6 100644 --- a/server/src/lib/ciscoController.js +++ b/server/src/lib/ciscoController.js @@ -107,7 +107,7 @@ export async function getOnlineWifiDevices() { apName: client.AP, status: client.ST == 'Online' ? 'ONLINE' : 'OFFLINE', controller: 'Cisco', - signalStrength: client.SS, + signalStrength: client.SS || null, frequency: client.FB, protocol: client.PT, speed: client.SD, diff --git a/server/src/lib/unifiController.js b/server/src/lib/unifiController.js index f90a7de..26eb120 100644 --- a/server/src/lib/unifiController.js +++ b/server/src/lib/unifiController.js @@ -191,7 +191,7 @@ export async function getOnlineWifiDevices() { apName: accessPoints[0].find(ap => ap.mac === client.ap_mac).name, status: 'ONLINE', controller: 'UniFi', - signalStrength: client.signal, + signalStrength: client.signal || null, frequency: null, protocol: null, speed: Math.floor(client.tx_rate / 1000), diff --git a/server/src/lib/wifiStats.js b/server/src/lib/wifiStats.js index 8ae551b..82e327e 100644 --- a/server/src/lib/wifiStats.js +++ b/server/src/lib/wifiStats.js @@ -42,7 +42,9 @@ async function generateStatsForAccessPoint(mac) { timestamp: timestamp.toISOString(), clients: dbStats._count._all, - avgSignalStrength: Math.floor(dbStats._avg.signalStrength, 0), + avgSignalStrength: dbStats.clients + ? Math.floor(dbStats._avg.signalStrength, 0) + : null, minSignalStrength: dbStats._min.signalStrength, maxSignalStrength: dbStats._max.signalStrength, diff --git a/server/src/resolvers/AccessPoint.js b/server/src/resolvers/AccessPoint.js index 0820cde..8be82e9 100644 --- a/server/src/resolvers/AccessPoint.js +++ b/server/src/resolvers/AccessPoint.js @@ -20,15 +20,21 @@ export const AccessPoint = { usage: (parent, data, context, info) => parent.usage.toString(), - stats: async (parent, { take, dateIn, dateOut }, context, info) => - prisma.wifiStats.findMany({ + stats: async (parent, { take, dateIn, dateOut }, context, info) => { + const stats = await prisma.wifiStats.findMany({ where: { accessPoint: { - id: parent.id + id: parent.id, + timestamp_gte: dateIn, + timestamp_lte: dateOut } }, + orderBy: { timestamp: 'desc' }, take - }), + }) + + return stats.reverse() + }, latestStats: async (parent, data, context, info) => prisma.wifiStats.findFirst({ diff --git a/server/src/resolvers/WifiStats.js b/server/src/resolvers/WifiStats.js index 75aaaae..ba137b1 100644 --- a/server/src/resolvers/WifiStats.js +++ b/server/src/resolvers/WifiStats.js @@ -1,4 +1,5 @@ const WifiStats = { + timestamp: parent => parent.timestamp.toString(), avgUsage: parent => parent.avgUsage.toString(), sumUsage: parent => parent.sumUsage.toString() } diff --git a/web/package-lock.json b/web/package-lock.json index b9dca56..39618bc 100755 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -11,6 +11,7 @@ "@mdi/font": "^6.6.96", "apollo-link-ws": "^1.0.20", "apollo-utilities": "^1.3.4", + "chart.js": "^3.8.0", "date-fns": "^2.28.0", "eslint": "^6.8.0", "qrcode.vue": "^1.7.0", @@ -18,6 +19,7 @@ "validator": "^13.7.0", "vue": "^2.6.14", "vue-apollo": "^3.1.0", + "vue-chartjs": "^4.1.1", "vue-json-pretty": "^1.8.2", "vue-router": "^3.5.3", "vue-the-mask": "^0.11.1", @@ -8789,6 +8791,11 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "node_modules/chart.js": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.8.0.tgz", + "integrity": "sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg==" + }, "node_modules/check-types": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", @@ -22410,6 +22417,15 @@ "graphql-tag": "^2" } }, + "node_modules/vue-chartjs": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-4.1.1.tgz", + "integrity": "sha512-rKIQ3jPrjhwxjKdNJppnYxRuBSrx4QeM3nNHsfIxEqjX6QS4Jq6e6vnZBxh2MDpURDC2uvuI2N0eIt1cWXbBVA==", + "peerDependencies": { + "chart.js": "^3.7.0", + "vue": "^3.0.0-0 || ^2.6.0" + } + }, "node_modules/vue-cli-plugin-apollo": { "version": "0.22.2", "resolved": "https://registry.npmjs.org/vue-cli-plugin-apollo/-/vue-cli-plugin-apollo-0.22.2.tgz", @@ -31273,6 +31289,11 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "chart.js": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.8.0.tgz", + "integrity": "sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg==" + }, "check-types": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", @@ -42126,6 +42147,12 @@ "throttle-debounce": "^2.1.0" } }, + "vue-chartjs": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-4.1.1.tgz", + "integrity": "sha512-rKIQ3jPrjhwxjKdNJppnYxRuBSrx4QeM3nNHsfIxEqjX6QS4Jq6e6vnZBxh2MDpURDC2uvuI2N0eIt1cWXbBVA==", + "requires": {} + }, "vue-cli-plugin-apollo": { "version": "0.22.2", "resolved": "https://registry.npmjs.org/vue-cli-plugin-apollo/-/vue-cli-plugin-apollo-0.22.2.tgz", diff --git a/web/package.json b/web/package.json index 67868c3..957a113 100755 --- a/web/package.json +++ b/web/package.json @@ -12,6 +12,7 @@ "@mdi/font": "^6.6.96", "apollo-link-ws": "^1.0.20", "apollo-utilities": "^1.3.4", + "chart.js": "^3.8.0", "date-fns": "^2.28.0", "eslint": "^6.8.0", "qrcode.vue": "^1.7.0", @@ -19,6 +20,7 @@ "validator": "^13.7.0", "vue": "^2.6.14", "vue-apollo": "^3.1.0", + "vue-chartjs": "^4.1.1", "vue-json-pretty": "^1.8.2", "vue-router": "^3.5.3", "vue-the-mask": "^0.11.1", diff --git a/web/src/components/Charts/AccessPointClientsChart.vue b/web/src/components/Charts/AccessPointClientsChart.vue new file mode 100644 index 0000000..a5c4dcb --- /dev/null +++ b/web/src/components/Charts/AccessPointClientsChart.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/web/src/components/Charts/AccessPointSignalStrengthChart.vue b/web/src/components/Charts/AccessPointSignalStrengthChart.vue new file mode 100644 index 0000000..22a3558 --- /dev/null +++ b/web/src/components/Charts/AccessPointSignalStrengthChart.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/web/src/views/AccessPoints/clients.vue b/web/src/views/AccessPoints/clients.vue index 1e29a09..dc49588 100644 --- a/web/src/views/AccessPoints/clients.vue +++ b/web/src/views/AccessPoints/clients.vue @@ -41,6 +41,17 @@ + + + + + + + + + + + ({ showDialog: true, filter: '' @@ -99,6 +117,19 @@ export default { controller notes updatedAt + + stats(take: 100) { + id + timestamp + clients + avgSignalStrength + minSignalStrength + maxSignalStrength + avgClientUptime + maxClientUptime + avgUsage + } + wifiDevices { id hostname @@ -112,6 +143,7 @@ export default { protocol speed usage + user { displayName sAMAccountName