added source files

This commit is contained in:
Bogdan Pilyugin 2023-08-20 12:36:42 +02:00
parent a299fd7298
commit aa4d6deafd
13 changed files with 644 additions and 0 deletions

11
CardActions.vue Normal file
View File

@ -0,0 +1,11 @@
<template>
<q-card-actions>
<q-btn flat v-on:click="SendAndRequest(senddata, 1, 0, 'mykey', true)">Apply</q-btn>
<q-btn flat v-on:click="SendAndRequest(senddata, 1, 1, 'mykey', true)">Save</q-btn>
<q-btn flat v-on:click="SendAndRequest(senddata, 1, 2, 'mykey', true)">Save&Reboot</q-btn>
</q-card-actions>
</template>
<script setup>
import { SendAndRequest } from "boot/network";
</script>

48
EssentialLink.vue Normal file
View File

@ -0,0 +1,48 @@
<template>
<q-item clickable tag="a" target="_self" :href="link">
<q-item-section v-if="icon" avatar>
<q-icon :name="icon" />
</q-item-section>
<q-item-section class="menu">
<q-item-label>{{ title }}</q-item-label>
<q-item-label caption>{{ caption }}</q-item-label>
</q-item-section>
</q-item>
</template>
<style>
.menu {
font-family: monospace;
font-size: larger;
}
</style>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "EssentialLink",
props: {
title: {
type: String,
required: true,
},
caption: {
type: String,
default: "",
},
link: {
type: String,
default: "#",
},
icon: {
type: String,
default: "",
},
},
});
</script>

67
SelectWiFiDialog.vue Normal file
View File

@ -0,0 +1,67 @@
<template>
<q-dialog ref="dialogRef" @hide="onDialogHide">
<q-card class="q-dialog-plugin">
<div class="q-pa-md q-gutter-md">
<q-card-section>
<q-inner-loading :showing="visible" label="Scaning WiFi..." label-class="text-teal"
label-style="font-size: 1.1em" />
</q-card-section>
<q-card-section>
<q-table title="WiFi networks" :rows="scandata.wifi_scan_res" :columns="columns" row-key="ssid"
hide-no-data="true" wrap-cells="true" @row-click="ClickOnRaw" />
</q-card-section>
<q-card-actions>
<q-btn label="OK" @click="onOKClick" />
<q-btn label="Cancel" @click="onDialogCancel" />
</q-card-actions>
</div>
</q-card>
</q-dialog>
</template>
<script setup>
import { useDialogPluginComponent } from 'quasar'
import { PostData } from "boot/network";
import { reactive, ref } from 'vue';
defineEmits([
// REQUIRED; need to specify some events that your
// component will emit through useDialogPluginComponent()
...useDialogPluginComponent.emits
])
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
// dialogRef - Vue ref to be applied to QDialog
// onDialogHide - Function to be used as handler for @hide on QDialog
// onDialogOK - Function to call to settle dialog with "ok" outcome
// example: onDialogOK() - no payload
// example: onDialogOK({ /*...*/ }) - with payload
// onDialogCancel - Function to call to settle dialog with "cancel" outcome
// this is part of our example (so not required)
function onOKClick() {
// on OK, it is REQUIRED to
// call onDialogOK (with optional payload)
onDialogOK()
// or with payload: onDialogOK({ ... })
// ...and it will also hide the dialog automatically
}
function ClickOnRaw(evt, row, index) {
alert(`clicked SSID ${row.ssid}`)
}
function onDataReady() {
visible.value = false;
}
let visible = ref(true);
const scandata = reactive({ wifi_scan_res: 10 });
PostData({ wifi_scan: 1 }, 2, 0, () => { });
setTimeout(() => { PostData(scandata, 2, 0, () => onDataReady()) }, 7000);
const columns = [
{ name: 'ssid', label: 'SSID', align: 'left', field: 'ssid', sortable: true },
{ name: 'rssi', label: 'RSSI', field: 'rssi', sortable: true },
{ name: 'ch', label: 'CHANNEL', field: 'ch', sortable: true },
]
</script>

45
cards/EthSetCard.vue Normal file
View File

@ -0,0 +1,45 @@
<template>
<q-card flat bordered class="card" v-show="data.eth_visible">
<q-card-section>
<div class="text-h6">ETHERNET</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<q-toggle :dense="true" v-model="data.eth_enab" label="Ethernet enable" />
<q-input :dense="true" v-model="data.eth_ip" label="IP address:" />
<q-input :dense="true" v-model="data.eth_mask" label="Subnet mask:" />
<q-input :dense="true" v-model="data.eth_gw" label="Gateway address:" />
<q-toggle :dense="true" v-model="data.eth_isdhcp" label="DHCP enabled"></q-toggle>
<q-input :dense=true v-model="data.eth_dns1" label="DNS1:" />
<q-input :dense=true v-model="data.eth_dns2" label="DNS2:" />
<q-input :dense=true v-model="data.eth_dns3" label="DNS3:" />
<q-input :dense=true v-model="data.eth_mac" label="MAC:" />
</div>
</div>
</q-card-section>
<q-card-actions>
<q-btn flat v-on:click="SendAndRequest(data, 1, 0, 'mykey', true)">Apply</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 1, 'mykey', true)">Save</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 2, 'mykey', true)">Save&Reboot</q-btn>
</q-card-actions>
</q-card>
</template>
<script setup>
import { reactive } from "vue";
import { SendAndRequest } from "boot/network";
defineOptions({
name: 'EthSetCard'
})
const init = {
eth_visible: false,
eth_enab: true, eth_isdhcp: true, eth_ip: "", eth_mask: "",
eth_gw: "", eth_dns1: "", eth_dns2: "", eth_dns3: "", eth_mac: ""
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
</script>

41
cards/FirmwareCard.vue Normal file
View File

@ -0,0 +1,41 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">FIRMWARE</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<q-toggle :dense="true" v-model="data.ota_enab" label="Eanble OTA autoudate" />
<q-toggle :dense="true" v-model="data.res_ota_enab" label="Enable reset after update" />
<q-input :dense="true" v-model="data.ota_url" label="OTA firmware file URL" />
<q-input :dense="true" v-model="data.ota_auto_int" label="New firmware check interval, sec" />
<div>Current firmware version:: {{ data.fw_rev }}</div>
<div>Available firmware version:: {{ data.fw_rev }}</div>
</div>
</div>
</q-card-section>
<q-card-actions>
<q-btn flat v-on:click="SendAndRequest(data, 1, 0, 'mykey', true)">Apply</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 1, 'mykey', true)">Save</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 2, 'mykey', true)">Save&Reboot</q-btn>
</q-card-actions>
</q-card>
</template>
<script setup>
import { reactive } from "vue";
import { SendAndRequest } from "boot/network";
defineOptions({
name: 'FirmwareCard'
})
const init = {
ota_enab: false, res_ota_enab: false, ota_url: "", ota_auto_int: 0, fw_rev: ""
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
</script>

44
cards/HomeCard.vue Normal file
View File

@ -0,0 +1,44 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">Home</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<div>{{ timestr }}</div>
<div>Uptime: {{ uptimestr }}</div>
</div>
</div>
</q-card-section>
</q-card>
</template>
<script setup>
import { computed, onUnmounted, reactive, onMounted } from "vue";
import { SendAndRequest } from "boot/network";
import { secondsToHms } from "boot/helpers"
defineOptions({
name: 'HomeCard'
})
const init = {
time: 0,
uptime: 0
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
let intervalId
onMounted(() => {
intervalId = setInterval(() => {
SendAndRequest(data, 2, 0, 'mykey', false);
}, 1000)
})
onUnmounted(() => clearInterval(intervalId))
const timestr = computed({ get() { return (new Date(data.time * 1000).toISOString()) } })
const uptimestr = computed({ get() { return (secondsToHms(data.uptime)) } })
</script>

46
cards/MQTT1Card.vue Normal file
View File

@ -0,0 +1,46 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">MQTT 1</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<q-toggle :dense="true" v-model="data.mqtt_1_enab" label="Eanble MQTT 1" />
<q-input :dense="true" v-model="data.mqtt_1_serv" label="MQTT broker URL " />
<q-input :dense="true" v-model="data.mqtt_1_port" label="MQTT broker port " />
<q-input :dense="true" v-model="data.mqtt_1_syst" label="Global system name " />
<q-input :dense="true" v-model="data.mqtt_1_group" label="Group name " />
<q-input :dense="true" v-model="data.mqtt_1_clid" label="Device ID prefix" />
<q-input :dense="true" v-model="data.mqtt_1_uname" label="Login" />
<q-input :dense="true" v-model="data.mqtt_1_pass" label="Password" />
</div>
</div>
</q-card-section>
<q-card-actions>
<q-btn flat v-on:click="SendAndRequest(data, 1, 0, 'mykey', true)">Apply</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 1, 'mykey', true)">Save</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 2, 'mykey', true)">Save&Reboot</q-btn>
</q-card-actions>
</q-card>
</template>
<script setup>
import { reactive } from "vue";
import { SendAndRequest } from "boot/network";
const init = {
mqtt_1_enab: false,
mqtt_1_serv: "",
mqtt_1_port: 1000,
mqtt_1_syst: "",
mqtt_1_group: "",
mqtt_1_clid: "",
mqtt_1_uname: "",
mqtt_1_pass: ""
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
</script>

51
cards/MQTT2Card.vue Normal file
View File

@ -0,0 +1,51 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">MQTT 2</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<q-toggle :dense="true" v-model="data.mqtt_2_enab" label="Eanble MQTT 2" />
<q-input :dense="true" v-model="data.mqtt_2_serv" label="MQTT broker URL " />
<q-input :dense="true" v-model="data.mqtt_2_port" label="MQTT broker port " />
<q-input :dense="true" v-model="data.mqtt_2_syst" label="Global system name " />
<q-input :dense="true" v-model="data.mqtt_2_group" label="Group name " />
<q-input :dense="true" v-model="data.mqtt_2_clid" label="Device ID prefix" />
<q-input :dense="true" v-model="data.mqtt_2_uname" label="Login" />
<q-input :dense="true" v-model="data.mqtt_2_pass" label="Password" />
</div>
</div>
</q-card-section>
<q-card-actions>
<q-btn flat v-on:click="SendAndRequest(data, 1, 0, 'mykey', true)">Apply</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 1, 'mykey', true)">Save</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 2, 'mykey', true)">Save&Reboot</q-btn>
</q-card-actions>
<CardActions />
</q-card>
</template>
<script setup>
import { reactive } from "vue";
import { SendAndRequest } from "boot/network";
const init = {
mqtt_2_enab: false,
mqtt_2_serv: "",
mqtt_2_port: 1000,
mqtt_2_syst: "",
mqtt_2_group: "",
mqtt_2_clid: "",
mqtt_2_uname: "",
mqtt_2_pass: ""
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
</script>

39
cards/SNTPCard.vue Normal file
View File

@ -0,0 +1,39 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">SNTP</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<q-toggle :dense="true" v-model="data.sntp_enab" label="Eanble SNTP" />
<q-input :dense="true" v-model="data.sntp_serv1" label="SNTP server 1:" />
<q-input :dense="true" v-model="data.sntp_serv2" label="SNTP server 2:" />
<q-input :dense="true" v-model="data.sntp_serv3" label="SNTP server 3:" />
</div>
</div>
</q-card-section>
<q-card-actions>
<q-btn flat v-on:click="SendAndRequest(data, 1, 0, 'mykey', true)">Apply</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 1, 'mykey', true)">Save</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 2, 'mykey', true)">Save&Reboot</q-btn>
</q-card-actions>
</q-card>
</template>
<script setup>
import { reactive } from "vue";
import { SendAndRequest } from "boot/network";
const init = {
sntp_serv1: "",
sntp_serv2: "",
sntp_serv3: "",
sntp_enab: false
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
</script>

65
cards/StatCard.vue Normal file
View File

@ -0,0 +1,65 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">INFO</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<div>{{ timestr }}</div>
<div>Uptime: {{ uptimestr }}</div>
<div>WiFi signal: {{ data.wifi_level }}</div>
<q-separator inset />
<div>Ethernet state: {{ data.eth_stat }}</div>
<div>WiFi state: {{ data.wifi_stat }}</div>
<div>GPRS state: {{ data.gsm_stat }}</div>
<q-separator inset />
<div>MQTT1 state: {{ data.mqtt_1_stat }}</div>
<div>MQTT2 state: {{ data.mqtt_2_stat }}</div>
<q-separator inset />
<div>Free RAM: {{ data.free_ram }}</div>
<div>Minimal free RAM: {{ data.free_ram_min }}</div>
</div>
</div>
</q-card-section>
</q-card>
</template>
<script setup>
import { computed, onUnmounted, reactive, onMounted } from "vue";
import { SendAndRequest } from "boot/network";
import { secondsToHms } from "boot/helpers"
defineOptions({
name: 'StatCard'
})
const init = {
time: 0,
uptime: 0,
wifi_level: "",
eth_stat: "",
wifi_stat: "",
gsm_stat: "",
mqtt_1_stat: "",
mqtt_2_stat: "",
free_ram: 0,
free_ram_min: 0
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
let intervalId
onMounted(() => {
intervalId = setInterval(() => {
SendAndRequest(data, 2, 0, 'mykey', false);
}, 1000)
})
onUnmounted(() => clearInterval(intervalId))
const timestr = computed({ get() { return (new Date(data.time * 1000).toISOString()) } })
const uptimestr = computed({ get() { return (secondsToHms(data.uptime)) } })
</script>

43
cards/SystemCard.vue Normal file
View File

@ -0,0 +1,43 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">SYSTEM</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<q-input :dense="true" v-model="data.net_bios_name" label="Device bios name" />
<q-input :dense="true" v-model="data.sys_name" label="User name" />
<q-input :dense="true" v-model="data.sys_pass" label="User password" />
<div>Device model: {{ data.model_name }}</div>
<div>Hardware revision: {{ data.hw_rev }}</div>
<div>Firmware version: {{ data.fw_rev }}</div>
<div>IDF version: {{ data.idf_rev }}</div>
<div>Build date: {{ data.build_date }}</div>
<div>Serial number: {{ data.ser_num }}</div>
</div>
</div>
</q-card-section>
<q-card-actions>
<q-btn flat v-on:click="SendAndRequest(data, 1, 0, 'mykey', true)">Apply</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 1, 'mykey', true)">Save</q-btn>
<q-btn flat v-on:click="SendAndRequest(data, 1, 2, 'mykey', true)">Save&Reboot</q-btn>
</q-card-actions>
</q-card>
</template>
<script setup>
import { reactive } from "vue";
import { SendAndRequest } from "boot/network";
defineOptions({
name: 'SystemCard'
})
const init = {
net_bios_name: "", sys_name: "", sys_pass: "",
model_name: "", hw_rev: 0, fw_rev: "", idf_rev: "", build_date: "", ser_num: ""
}
const data = reactive(init);
SendAndRequest(data, 2, 0, 'mykey', false);
</script>

80
cards/WifiSetCard.vue Normal file
View File

@ -0,0 +1,80 @@
<template>
<q-card flat bordered class="card">
<q-card-section>
<div class="text-h6">WiFi</div>
</q-card-section>
<q-card-section class="q-pt-none">
<div class="q-pa-md">
<div class="q-gutter-md q-pa-none q-pb-none">
<q-toggle :dense="true" v-model="data.wifi_enab" label="WiFi enable" />
<q-btn :dense="true" label="Scan WiFi" @click="OpenScanDialog()"></q-btn>
<q-select :dense="true" v-model="wifimodestr" :options="wifimodes" :map-options="true" :emit-value="true"
label="WiFi mode"></q-select>
<q-input :dense="true" v-model="wifipwr" label="Max power, dBm" />
<q-input :dense="true" v-model="data.wifi_ap_ssid" label="WiFi network name(AP):" />
<q-input :dense="true" v-model="data.wifi_ap_key" label="WiFi network key(AP):" />
<q-input :dense="true" v-model="data.wifi_ap_ip" label="IP address(AP):" />
<q-input :dense="true" v-model="data.wifi_sta_ssid" label="WiFi network name(CLN):" />
<q-input :dense="true" v-model="data.wifi_sta_key" label="WiFi network key(CLN):" />
<q-toggle :dense="true" v-model="data.wifi_isdhcp" label="DHCP enabled"></q-toggle>
<q-input :dense="true" v-model="data.wifi_sta_ip" label="IP address(CLN):" />
<q-input :dense="true" v-model="data.wifi_sta_mask" label="Subnet mask(CLN):" />
<q-input :dense="true" v-model="data.wifi_sta_gw" label="Gateway address(CLN):" />
<q-input :dense=true v-model="data.wifi_dns1" label="DNS1:" />
<q-input :dense=true v-model="data.wifi_dns2" label="DNS2:" />
<q-input :dense=true v-model="data.wifi_dns3" label="DNS3:" />
<q-input :dense=true v-model="data.wifi_sta_mac" label="MAC(CLN):" />
<q-input :dense=true v-model="data.wifi_ap_mac" label="MAC(AP):" />
</div>
</div>
</q-card-section>
<CardActions :senddata="data"></CardActions>
</q-card>
</template>
<script setup>
import { computed, reactive } from "vue";
import { SendAndRequest } from "components/webguicomp/network";
import { useQuasar } from 'quasar'
import SelectWiFiDialog from 'components/webguicomp/SelectWiFiDialog.vue'
import CardActions from "components/webguicomp/CardActions.vue"
const $q = useQuasar();
defineOptions({
name: 'WifiSetCard'
})
const init = {
wifi_enab: true, wifi_mode: 1, wifi_power: 0, wifi_ap_ssid: "", wifi_ap_key: "",
wifi_ap_ip: "", wifi_sta_ssid: "", wifi_sta_key: "", wifi_isdhcp: true, wifi_sta_ip: "",
wifi_sta_mask: "", wifi_sta_gw: "", wifi_dns1: "", wifi_dns2: "", wifi_dns3: "",
wifi_sta_mac: "", wifi_ap_mac: ""
}
const wifimodes = [
{ label: 'Station (STA)', value: '1' },
{ label: 'Access point (AP)', value: '2' },
{ label: 'Mixed mode (AP+STA)', value: '3' }];
const data = reactive(init);
const wifimodestr = computed({
get() { return (data.wifi_mode).toString() },
set(val) { data.wifi_mode = Number(val); }
})
const wifipwr = computed({
get() { return (data.wifi_power) / 4 },
set(val) { data.wifi_power = val * 4; }
})
function OpenScanDialog() {
$q.dialog({
component: SelectWiFiDialog
});
};
SendAndRequest(data, 2, 0, 'mykey', false);
</script>

64
network.js Normal file
View File

@ -0,0 +1,64 @@
import { api } from "boot/axios";
import { sha256 } from "js-sha256";
import { Notify, Dialog } from "quasar";
const API_URL = "/api";
const SHA256_HMAC_KEY = "mykey";
function ShowSaveDialog(apltype) {
const opername = ['Data applying...', 'Data saving...', 'Data saving and reboot...'];
let step = (apltype == 2) ? 1 : 10;
let percentage = 0;
const dialog = Dialog.create({ message: opername[apltype], progress: true, persistent: true, ok: false })
const interval = setInterval(() => {
percentage = Math.min(100, percentage + step);
dialog.update({
message: `${opername[apltype]} ${percentage}%`
})
if (percentage === 100) {
clearInterval(interval);
setTimeout(() => { dialog.hide() }, 350)
}
}, 100)
}
function PostData(varlist, messtype, applytype, onfinished) {
var pld = {};
var data = {};
data.msgid = Math.floor(Date.now() / 1000);
data.time = new Date().toISOString();
data.msgtype = messtype;
data.payloadtype = 1;
data.payload = {};
data.payload.applytype = applytype;
data.payload.variables = varlist;
pld.data = data;
pld.signature = sha256.hmac(SHA256_HMAC_KEY, JSON.stringify(data));
api
.post(API_URL, JSON.stringify(pld), {
headers: { "Content-Type": "application/json" },
})
.then((response) => {
var resp = response.data.data.payload.variables;
for (var k in resp) varlist[k] = resp[k];
if (onfinished) onfinished();
})
.catch((err) => {
Notify.create({ color: "negative", position: "top", message: err.message, icon: "report_problem", });
});
}
function SendAndRequest(varlist, mstp, apltp, shakey, okreport) {
var onfinish = (okreport) ? () => { ShowSaveDialog(apltp) } : null;
PostData(varlist, mstp, apltp, onfinish);
}
export { SendAndRequest, PostData };