Compare commits

...

6 Commits

Author SHA1 Message Date
Jordan Hsu aa9c8c21b7 [modify] trigger mqtt route 2021-12-24 11:40:23 +08:00
Jordan Hsu a239223361 [add] trigger chart 2021-12-22 17:33:03 +08:00
Jordan Hsu e0341356c8 [add] trigger list ui with mqtt 2021-12-21 16:26:45 +08:00
Jordan Hsu b56c753063 [add] trigger list ui layout 2021-12-21 10:12:39 +08:00
Jordan Hsu 04741d8a77 [modify] triggerList to vuex 2021-12-21 10:10:34 +08:00
Jordan Hsu 3721e4a515 [add] device overview with trigger 2021-12-20 16:11:01 +08:00
22 changed files with 1135 additions and 1 deletions
+79 -1
View File
@@ -38,7 +38,7 @@
<div class="row flex">
<div
class="flex sm12 xl6 md12 xs12 ma-0"
class="flex sm12 xl12 md12 xs12 ma-0"
v-for="device in controller.devices" :key="device.addr"
>
<div v-if="!controller.isScan || device.status == 'connected'">
@@ -94,6 +94,35 @@
</va-card>
</div>
</div>
<div
class="flex sm12 xl6 md12 xs12 ma-0"
v-for="trigger in triggerList" :key="trigger.mac"
>
<div v-if="!controller.isScan">
<va-card
style="background-color: #f8f8f8; box-shadow: 5px 5px 0 0 #f1f1f1;"
class="ma-0 pa-0"
>
<va-item :key="trigger.mac" class="pa-0 ma-0"
>
<!-- <va-item-section avatar class="ml-1">
<va-avatar style="border-radius: 0;">
<img :src="trigger.pic" :alt="trigger.name">
</va-avatar>
</va-item-section> -->
<va-item-section class="ml-3">
<va-item-label>
{{ trigger.name }}
<va-badge class="px-1 py-0 ml-2 mt-0" color="success">connected</va-badge>
</va-item-label>
<va-item-label caption>
{{ trigger.mac }}
</va-item-label>
</va-item-section>
</va-item>
</va-card>
</div>
</div>
</div>
</div>
@@ -140,12 +169,18 @@
import api from '@/data/api/index'
import { taskInfo } from '@/data/task/TaskInfo'
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'devices-overview',
components: {
FulfillingBouncingCircleSpinner,
},
computed: {
...mapFields('device', [
'triggerList',
]),
},
created () {
},
data () {
@@ -248,6 +283,44 @@ export default {
})
}
},
'+/data-server/trigger_manager/#' (data, topic) {
const mes = new TextDecoder('utf-8').decode(data)
const topicSplit = topic.split('/')
const baseIndex = topicSplit.indexOf('trigger_manager')
const actionIndex = baseIndex + 1
const action = topicSplit[actionIndex]
const macIndex = baseIndex + 2
let _mac
if (topicSplit.length - 1 >= macIndex) {
_mac = topicSplit[macIndex]
}
let foundIndex
let mesJson
switch (action) {
case 'info_all': // control_ID/data-server/trigger_manager/info_all
this.triggerList = JSON.parse(mes)
break
case 'register': // control_ID/data-server/trigger_manager/register
mesJson = JSON.parse(mes)
foundIndex = this.triggerList.findIndex(o => o.mac === mesJson.mac)
if (foundIndex < 0) { // -1: not found
this.triggerList.push(mesJson)
} else {
this.triggerList[foundIndex] = mesJson
}
break
case 'remove': // control_ID/data-server/trigger_manager/remove/device_mac
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
this.triggerList.splice(foundIndex, 1)
break
case 'info': // control_ID/data-server/trigger_manager/info/device_mac
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
this.triggerList[foundIndex] = mesJson
break
default:
break
}
},
async '+/broadcast' (data, topic) {
const topicSplit = topic.split('/')
const mes = String.fromCharCode.apply(null, data).split(':')
@@ -379,6 +452,7 @@ export default {
this.mqttSub(controller.id + '/hardware_device_connect/+')
this.mqttSub(controller.id + '/hardware_scan/+')
this.mqttSub(controller.id + '/broadcast')
this.mqttSub(controller.id + '/data-server/trigger_manager/#')
})
},
pageMqttUnSub: function () {
@@ -389,6 +463,7 @@ export default {
this.mqttUnSub(controller.id + '/hardware_device_connect/+')
this.mqttUnSub(controller.id + '/hardware_scan/+')
this.mqttUnSub(controller.id + '/broadcast')
this.mqttUnSub(controller.id + '/data-server/trigger_manager/#')
})
},
pageInitPub: function () {
@@ -403,6 +478,8 @@ export default {
this.mqttPub(controller.id + '_user', JSON.stringify({
header: 'hardware_info/0',
}))
this.mqttPub(controller.id + '/client/trigger_manager/scan', '{}')
this.mqttPub(controller.id + '/client/trigger_manager/info_all', '{}')
// this.mqttPub(controller.id + '_user', JSON.stringify({
// header: 'device_update_usb/0',
// }))
@@ -427,6 +504,7 @@ export default {
this.mqttPub(controller.id + '_user', JSON.stringify({
header: 'hardware_scan/0',
}))
this.mqttPub(controller.id + '/client/trigger_manager/scan', '{}')
}
}
})
@@ -78,6 +78,14 @@
@remove="removeChartCheck(chart.chartID)"
/>
</div>
<div
v-for="trigger in triggerList"
:key="trigger.id"
>
<trigger-chart
:mac="trigger.mac"
/>
</div>
</div>
<div style="height: 150px;">
@@ -100,6 +108,7 @@ import { chartData } from '../../../data/task/ChartsManagement'
import { taskInfo } from '../../../data/task/TaskInfo'
import CanvasChart from './chart/CanvasChart'
import TaskDevices from './controller/TaskDevices'
import TriggerChart from './chart/TriggerChart'
// import api from '@/data/api'
import { mapFields } from 'vuex-map-fields'
// import TaskFormula from './formula/TaskFormula'
@@ -111,12 +120,16 @@ export default {
components: {
CanvasChart,
TaskDevices,
TriggerChart,
// TaskFormula,
},
computed: {
...mapFields('taskContent', [
'deviceList',
]),
...mapFields('device', [
'triggerList',
]),
},
data () {
return {
@@ -230,6 +243,52 @@ export default {
await taskInfo.updateSdCardStatus(String.fromCharCode.apply(null, data))
this.refreshDevicesWindow()
},
'+/data-server/trigger_manager/#' (data, topic) {
const mes = new TextDecoder('utf-8').decode(data)
const topicSplit = topic.split('/')
const baseIndex = topicSplit.indexOf('trigger_manager')
const actionIndex = baseIndex + 1
const action = topicSplit[actionIndex]
const macIndex = baseIndex + 2
let _mac
if (topicSplit.length - 1 >= macIndex) {
_mac = topicSplit[macIndex]
}
let foundIndex
let mesJson
switch (action) {
case 'info_all': // control_ID/data-server/trigger_manager/info_all
this.triggerList = JSON.parse(mes)
break
case 'register': // control_ID/data-server/trigger_manager/register
mesJson = JSON.parse(mes)
foundIndex = this.triggerList.findIndex(o => o.mac === mesJson.mac)
if (foundIndex < 0) { // -1: not found
this.triggerList.push(mesJson)
} else {
this.triggerList[foundIndex] = mesJson
}
break
case 'remove': // control_ID/data-server/trigger_manager/remove/device_mac
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
this.triggerList.splice(foundIndex, 1)
break
case 'info': // control_ID/data-server/trigger_manager/info/device_mac
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
this.triggerList[foundIndex] = JSON.parse(mes)
break
case 'set_parameter': // control_ID/data-server/trigger_manager/set_parameter/device_mac
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
this.triggerList[foundIndex].parameter = JSON.parse(mes)
break
case 'runtime': // control_ID/data-server/trigger_manager/runtime/device_mac
foundIndex = this.triggerList.findIndex(o => o.mac === _mac)
mes === 'start' ? this.triggerList[foundIndex].status = 'RUNNING' : this.triggerList[foundIndex].status = 'CONNECTED'
break
default:
break
}
},
async '+/broadcast' (data, topic) {
const mes = String.fromCharCode.apply(null, data).split(':')
// let content
@@ -310,6 +369,7 @@ export default {
this.mqttSub(id + '/device_parameter/+')
this.mqttSub(id + '/device_parameter_value/+')
this.mqttSub(id + '/device_sd_card_status/+')
this.mqttSub(id + '/data-server/trigger_manager/#')
},
pageMqttUnSub: function (id) {
for (const device in taskInfo.getTaskInfo().deviceList) {
@@ -322,6 +382,7 @@ export default {
this.mqttUnSub(id + '/device_parameter/+')
this.mqttUnSub(id + '/device_parameter_value/+')
this.mqttUnSub(id + '/device_sd_card_status/+')
this.mqttUnSub(id + '/data-server/trigger_manager/#')
},
pageInit: async function () {
if (await this.$refs.devices_ref != null) {
@@ -340,6 +401,8 @@ export default {
header: 'hardware_device/0',
}))
await taskInfo.updateChartInfo()
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/scan', '{}')
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/info_all', '{}')
this.chartNumber = taskInfo.getTaskInfo().chartNumber
},
pageToast: function (mes) {
@@ -0,0 +1,205 @@
<template>
<div class="flex" :class="cardclass">
<va-card>
<chart :ref="'chart_ref'" :style="'width: '+ cardwidth + '; height: ' + cardheight + ';'" :options="sketchmapData" :auto-resize="true"></chart>
</va-card>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import { taskInfo } from '@/data/task/TaskInfo'
import { mapFields } from 'vuex-map-fields'
import deviceTypes from '@/store/modules/device/types'
export default {
name: 'TriggerChart',
components: {
},
computed: {
...mapFields('device', [
'triggerList',
'allChannels',
]),
},
props: {
mac: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
cardclass: ['xs12', 'md12', 'xl12', 'sm12'],
cardheight: '400px',
cardwidth: 'auto',
sketchmapData: {},
activeChannels: [],
}
},
mqtt: {
async '+/data-server/trigger_manager/#' (data, topic) {
const topicSplit = topic.split('/')
const baseIndex = topicSplit.indexOf('trigger_manager')
const actionIndex = baseIndex + 1
const action = topicSplit[actionIndex]
const macIndex = baseIndex + 2
let _mac
if (topicSplit.length - 1 >= macIndex) {
_mac = topicSplit[macIndex]
}
if (_mac === this.mac) {
switch (action) {
case 'set_parameter': // control_ID/data-server/trigger_manager/set_parameter/device_mac
await this.initActiveChannels()
this.initChart()
break
default:
break
}
}
},
'+/data-server/trigger_runtime/#' (data, topic) { // control_ID/data-server/trigger_runtime/pin_event/device_mac/channel
const mes = new TextDecoder('utf-8').decode(data)
const topicSplit = topic.split('/')
const baseIndex = topicSplit.indexOf('trigger_runtime')
const actionIndex = baseIndex + 1
const action = topicSplit[actionIndex]
const macIndex = baseIndex + 2
const channelIndex = baseIndex + 3
let _mac
if (topicSplit.length - 1 >= macIndex) {
_mac = topicSplit[macIndex]
}
let channel
if (topicSplit.length - 1 >= channelIndex) {
channel = topicSplit[channelIndex]
}
let mesJson
if (_mac === this.mac) {
switch (action) {
case 'pin_event':
mesJson = JSON.parse(mes)
this.addSketchMapData(mesJson.timestamp, mesJson.status === 'high' ? 3.3 : 0.0, channel)
break
default:
break
}
}
},
},
methods: {
addSketchMapData (timestamp, val, channel) {
const gridIndex = this.activeChannels.indexOf(channel)
this.sketchmapData.series[gridIndex].data.push([parseInt(timestamp), val])
if (this.sketchmapData.series[gridIndex].data.length > 10) {
this.sketchmapData.series[gridIndex].data.shift()
}
},
mqttSub: function (val) {
this.$mqtt.subscribe(val)
},
mqttUnSub: function (val) {
this.$mqtt.unsubscribe(val)
},
makeGrid (index, length) {
const _height = (100 / length) - 2 + '%'
const _top = index * (100 / length) + 2 + '%'
const _left = '0%'
const _right = '2%'
return {
index: index,
top: _top,
height: _height,
left: _left,
right: _right,
containLabel: true,
}
},
makeSeries (xAxisIndex, yAxisIndex) {
return {
type: 'line',
step: 'start',
data: [],
animation: false,
xAxisIndex: xAxisIndex,
yAxisIndex: yAxisIndex,
}
},
makeXAxis (gridIndex) {
return {
show: true,
type: 'time',
gridIndex: gridIndex,
splitNumber: 5,
min: 'dataMin',
max: 'dataMax',
}
},
makeYAxis (gridIndex) {
return {
type: 'value',
gridIndex: gridIndex,
splitNumber: 1,
splitLine: {
show: false,
},
axisLabel: {
formatter: function (value) {
return value + 'V'
},
},
min: 'dataMin',
max: 'dataMax',
}
},
async initActiveChannels () {
this.activeChannels = await this.deviceTriggerGetActiveChannels({ mac: this.mac })
},
initChart () {
this.clearChart()
const gridLength = this.activeChannels.length
for (let gridIndex = 0; gridIndex < gridLength; gridIndex++) {
this.sketchmapData.grid.push(this.makeGrid(gridIndex, gridLength))
this.sketchmapData.xAxis.push(this.makeXAxis(gridIndex))
this.sketchmapData.yAxis.push(this.makeYAxis(gridIndex))
this.sketchmapData.series.push(this.makeSeries(gridIndex, gridIndex))
}
this.sketchmapData.xAxis[gridLength - 1].show = true
},
clearChart () {
this.sketchmapData = {
xAxis: [],
yAxis: [],
tooltip: {
trigger: 'axis',
},
series: [],
grid: [],
}
},
...mapActions('device', [deviceTypes.trigger.getActiveChannels]),
},
mounted () {
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_manager/#')
this.mqttSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_runtime/#')
const obj = this.triggerList.find(o => o.mac === this.mac)
for (const index in this.allChannels) {
const key = 'channel_event_' + index
if (Object.keys(obj.parameter[key]).length !== 0) {
this.activeChannels.push(index)
}
}
this.initChart()
},
destroyed () {
this.mqttUnSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_manager/#')
this.mqttUnSub(taskInfo.getTaskInfo().controllerID + '/data-server/trigger_runtime/#')
this.clearChart()
},
}
</script>
@@ -48,12 +48,35 @@
</div>
</va-card>
<va-card>
<template slot="header">
<va-icon name="fa fa-bluetooth-b mr-3" color="primary"/>
<h5 class="mt-0 mb-0">TRIGGERS</h5>
</template>
<div v-if="state.LOADING" class="flex-center spinner-box mt-4 mb-5">
<fulfilling-bouncing-circle-spinner
:animation-duration="3000"
:color="this.$themes.primary"
:size="60"
>
</fulfilling-bouncing-circle-spinner>
</div>
<div class="flex row align--center">
<trigger-list
@start="startTrigger($event)"
@stop="stopTrigger($event)"
/>
</div>
</va-card>
</div>
</template>
<script>
import { FulfillingBouncingCircleSpinner } from 'epic-spinners'
import TaskDeviceList from './TaskDeviceList'
import TriggerList from './TriggerList'
// import TaskDeviceListGM from './neulive-gimer/TaskDeviceListGM'
import { taskInfo } from '../../../../data/task/TaskInfo'
import { chartData } from '../../../../data/task/ChartsManagement'
@@ -67,6 +90,7 @@ export default {
// TaskDeviceListGM,
FulfillingBouncingCircleSpinner,
TaskDeviceList,
TriggerList,
},
props: {
cardclass: {
@@ -321,6 +345,20 @@ export default {
device: taskInfo.getRawDeviceID(device.id),
}))
},
startTrigger (trigger) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/runtime', JSON.stringify({
mac: trigger.mac,
instruction: 'start',
}),
)
},
stopTrigger (trigger) {
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/runtime', JSON.stringify({
mac: trigger.mac,
instruction: 'stop',
}),
)
},
addDevice: async function (selectID) {
if (selectID == null) {
return false
@@ -0,0 +1,80 @@
<template>
<div class="flex sm12 xl12 md12 xs12">
<va-accordion v-for="trigger in triggerList" :key="trigger.id">
<va-collapse class="mb-2" :isOpenDefault='true'>
<span slot="header" >
<va-item :key="trigger.id" class="pa-0 ma-0"
>
<va-item-section class="ml-3" caption>
<va-item-label>
{{ trigger.name }}
</va-item-label>
<va-item-label caption>
{{ trigger.mac }}
</va-item-label>
</va-item-section>
</va-item>
<va-item class="pa-0 ma-0 mt-2">
<va-item-section class="ml-3">
<va-item-label>
<va-button @click.stop="start(trigger)" v-if="trigger.status !== 'RUNNING'" class="px-2 py-0 mr-0" color="success" small>START</va-button>
<va-button @click.stop="stop(trigger)" v-if="trigger.status === 'RUNNING'" class="px-2 py-0 mr-0" color="danger" small>STOP</va-button>
</va-item-label>
</va-item-section>
</va-item>
</span>
<div slot="body">
<div class="mt-0 mb-0" style="height: 350px; overflow-y: scroll; overflow-x: hidden;" :key="'detail' + trigger.id">
<div>
<trigger-control-window :mac="trigger.mac" />
</div>
</div>
</div>
</va-collapse>
</va-accordion>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
import TriggerControlWindow from '../trigger/TriggerControlWindow'
export default {
name: 'TriggerList',
components: {
TriggerControlWindow,
},
data () {
return {
}
},
computed: {
...mapFields('device', [
'triggerList',
]),
},
methods: {
start: async function (trigger) {
this.$emit('start', trigger)
this.pageToast('The trigger ' + trigger.name + ' has been started.')
},
stop: function (trigger) {
this.$emit('stop', trigger)
this.pageToast('The trigger ' + trigger.name + ' has been stopped.')
},
pageToast: function (mes) {
this.showToast(
mes,
{
icon: 'fa-bell',
position: 'bottom-right',
duration: 4000,
},
)
},
},
destroyed () {
},
}
</script>
@@ -0,0 +1,87 @@
<template>
<div class="row flex px-0 mx-0 my-0 py-0">
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0 my-0 py-2">
<p class="display-6">Action<p/>
</div>
<div class="flex sm7 xl7 md7 xs7 px-0 mx-0 my-0 py-0" :key="inputKey">
<!-- <p class="display-6">Method<p/> -->
<va-input
@mouseleave.native="itemChange()"
@keyup.enter="itemChange()"
@blur="itemChange()"
v-model="methodInput"
class="my-2"
label="Method"
/>
<va-input
@mouseleave.native="itemChange()"
@keyup.enter="itemChange()"
@blur="itemChange()"
v-model="dataInput"
class="mb-0"
label="Data"
/>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'Action',
components: {
},
computed: {
...mapFields('device', [
'triggerList',
]),
},
props: {
mac: {
type: String,
required: true,
},
channelIndex: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
inputKey: 0,
methodInput: '',
dataInput: '',
}
},
mqtt: {
},
methods: {
itemChange () {
const key = 'channel_event_' + this.channelIndex
const obj = this.triggerList.find(o => o.mac === this.mac)
obj.parameter[key].action = {
method: this.methodInput,
data: this.dataInput,
}
},
refresh () {
const key = 'channel_event_' + this.channelIndex
const obj = this.triggerList.find(o => o.mac === this.mac)
if (Object.keys(obj.parameter[key]).length !== 0) {
this.methodInput = obj.parameter[key].action.method
this.dataInput = obj.parameter[key].action.data
}
},
},
mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,52 @@
<template>
<div class="row flex sm12 xl12 md12 xs12 my-3 py-0">
<div class="flex sm4 xl4 md4 xs4 px-0 py-0 mx-0 my-0">
<p class="display-6"> CHANNEL {{ channelIndex + 1 }} <p/>
</div>
<div class="flex sm8 xl8 md8 xs8 px-0 py-0 mx-0 mt-1" :key="inputKey">
<mode :ref="'mode'" class="mb-1" :mac="mac" :channelIndex="channelIndex" />
</div>
</div>
</template>
<script>
import Mode from './Mode'
export default {
name: 'Channel',
components: {
Mode,
},
props: {
mac: {
type: String,
required: true,
},
channelIndex: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
inputKey: 0,
}
},
mqtt: {
},
methods: {
refresh () {
this.$refs.mode.refresh()
},
},
mounted () {
},
watch: {
},
destroyed () {
},
}
</script>
@@ -0,0 +1,74 @@
<template>
<div class="row flex px-0 mx-0 my-0 py-0">
<div class="flex sm5 xl5 md5 xs5 px-0 mx-0 my-0 py-2">
<p class="display-6">Description<p/>
</div>
<div class="flex sm7 xl7 md7 xs7 px-0 mx-0 my-0 py-0">
<va-input
@mouseleave.native="itemChange()"
@keyup.enter="itemChange()"
@blur="itemChange()"
:key="inputKey"
style="float: left;"
v-model="itemInput"
class="mb-0"
/>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'Description',
components: {
},
computed: {
...mapFields('device', [
'triggerList',
]),
},
props: {
mac: {
type: String,
required: true,
},
channelIndex: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
inputKey: 0,
itemInput: '',
}
},
mqtt: {
},
methods: {
itemChange () {
const key = 'channel_event_' + this.channelIndex
const obj = this.triggerList.find(o => o.mac === this.mac)
obj.parameter[key].description = this.itemInput
},
refresh () {
const key = 'channel_event_' + this.channelIndex
const obj = this.triggerList.find(o => o.mac === this.mac)
if (Object.keys(obj.parameter[key]).length !== 0) {
this.itemInput = obj.parameter[key].description
}
},
},
mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,64 @@
<template>
<div class="row flex px-0 mx-0 my-0 py-0">
<div class="flex sm4 xl4 md4 xs4 px-0 mx-0 my-0 py-2">
<p class="display-6">INTERVAL<p/>
</div>
<div class="flex sm4 xl4 md4 xs4 px-0 mx-0 my-0 py-0">
<va-input
@mouseleave.native="itemChange()"
@keyup.enter="itemChange()"
@blur="itemChange()"
:key="inputKey"
v-model="itemInput"
class="mb-0"
/>
</div>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'Interval',
components: {
},
computed: {
...mapFields('device', [
'triggerList',
]),
},
props: {
mac: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
inputKey: 0,
itemInput: 0.5,
}
},
mqtt: {
},
methods: {
itemChange () {
const obj = this.triggerList.find(o => o.mac === this.mac)
obj.parameter.runtime_interval = parseFloat(this.itemInput)
},
refresh () {
this.itemInput = this.triggerList.find(o => o.mac === this.mac).parameter.runtime_interval
},
},
async mounted () {
},
destroyed () {
},
watch: {
},
}
</script>
@@ -0,0 +1,136 @@
<template>
<div class="row">
<va-radio-button
v-for="(option, index) in optionMode"
:key="index"
v-model="selectMode"
:option="optionMode[index]"
:label="optionMode[index]"
class="pl-2"
@click.native.stop="itemChange(index)"
/>
<div v-show="selectMode === 'INPUT'" class="my-3 pl-3">
<ttl :ref="'ttl'" :mac="mac" :channelIndex="channelIndex" />
<description :ref="'desc'" :mac="mac" :channelIndex="channelIndex" />
<action :ref="'action'" :mac="mac" :channelIndex="channelIndex" />
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
import { mapFields } from 'vuex-map-fields'
import deviceTypes from '@/store/modules/device/types'
import Ttl from './Ttl'
import Description from './Description'
import Action from './Action'
export default {
name: 'Mode',
components: {
Ttl,
Description,
Action,
},
computed: {
...mapFields('device', [
'triggerList',
'allChannels',
]),
},
props: {
mac: {
type: String,
required: true,
},
channelIndex: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
selectMode: 'DISABLE',
optionMode: [
'DISABLE',
'INPUT',
'OUTPUT',
],
}
},
mqtt: {
},
methods: {
getBitMode (channelList) {
let channelSet = ''
for (let i = 3; i >= 0; i--) {
if (channelList.indexOf(i) >= 0) {
channelSet += '1'
} else {
channelSet += '0'
}
}
return parseInt(channelSet, 2)
},
async updateBitMode (obj) {
const outputChannels = await this.deviceTriggerGetOutputChannels({ mac: this.mac })
this.selectMode === 'OUTPUT' ? outputChannels.add(this.channelIndex) : outputChannels.delete(this.channelIndex)
obj.parameter.bitmode = this.getBitMode(Array.from(outputChannels))
},
itemChange () {
const key = 'channel_event_' + this.channelIndex
const obj = this.triggerList.find(o => o.mac === this.mac)
if (this.selectMode === 'INPUT') {
if (Object.keys(obj.parameter[key]).length === 0) {
obj.parameter[key] = {
ttl: 'high',
description: 'camera on',
action: {},
broadcast: 1,
}
}
this.$refs.ttl.itemChange()
this.$refs.desc.itemChange()
this.$refs.action.itemChange()
} else {
obj.parameter[key] = {}
}
this.updateBitMode(obj)
},
async refreshSelectMode () {
const outputChannels = await this.deviceTriggerGetOutputChannels({ mac: this.mac })
if (outputChannels.has(this.channelIndex)) {
this.selectMode = 'OUTPUT'
}
const inputChannels = await this.deviceTriggerGetInputChannels({ mac: this.mac })
if (inputChannels.includes(String(this.channelIndex))) {
this.selectMode = 'INPUT'
}
},
async refresh () {
await this.refreshSelectMode()
if (this.$refs.ttl != null) {
this.$refs.ttl.refresh()
}
if (this.$refs.desc != null) {
this.$refs.desc.refresh()
}
if (this.$refs.action != null) {
this.$refs.action.refresh()
}
},
...mapActions('device', [deviceTypes.trigger.getOutputChannels, deviceTypes.trigger.getInputChannels]),
},
mounted () {
},
watch: {
},
destroyed () {
},
}
</script>
@@ -0,0 +1,72 @@
<template>
<div>
<div style="text-align: right;">
<va-button small @click="updateParam"> SAVE </va-button>
</div>
<interval :ref="'interval'" :mac="mac" />
<div v-for="channelIndex in allChannels" :key="channelIndex">
<channel :ref="'channel'" :mac="mac" :channelIndex="channelIndex" />
</div>
</div>
</template>
<script>
import Interval from './Interval'
import Channel from './Channel'
import { taskInfo } from '@/data/task/TaskInfo'
import { mapFields } from 'vuex-map-fields'
export default {
name: 'TriggerControlWindow',
components: {
Interval,
Channel,
},
computed: {
...mapFields('device', [
'triggerList',
'allChannels',
]),
},
props: {
mac: {
type: String,
required: true,
},
},
created () {
},
data () {
return {
}
},
mqtt: {
},
methods: {
updateParam () {
const obj = this.triggerList.find(o => o.mac === this.mac)
this.mqttPub(taskInfo.getTaskInfo().controllerID + '/client/trigger_manager/set_parameter', JSON.stringify({
mac: obj.mac,
parameter_set: obj.parameter,
}),
)
},
mqttPub: function (topic, mes) {
this.$mqtt.publish(topic, mes)
},
},
mounted () {
if (this.$refs.interval != null) {
this.$refs.interval.refresh()
}
if (this.$refs.channel != null) {
this.$refs.channel.forEach(ch => ch.refresh())
}
},
watch: {
},
destroyed () {
},
}
</script>
@@ -0,0 +1,72 @@
<template>
<div class="row pl-2">
<va-radio-button
v-for="(option, index) in optionMode"
:key="index"
v-model="selectMode"
:option="optionMode[index]"
:label="optionMode[index]"
@click.native.stop="itemChange()"
/>
</div>
</template>
<script>
import { mapFields } from 'vuex-map-fields'
export default {
name: 'Ttl',
components: {
},
computed: {
...mapFields('device', [
'triggerList',
]),
},
props: {
mac: {
type: String,
required: true,
},
channelIndex: {
type: Number,
required: true,
},
},
created () {
},
data () {
return {
inputeKey: 0,
selectMode: 'HIGH',
optionMode: [
'HIGH',
'LOW',
],
}
},
mqtt: {
},
methods: {
itemChange () {
const key = 'channel_event_' + this.channelIndex
const obj = this.triggerList.find(o => o.mac === this.mac)
obj.parameter[key].ttl = this.selectMode.toLowerCase()
},
refresh () {
const key = 'channel_event_' + this.channelIndex
const obj = this.triggerList.find(o => o.mac === this.mac)
if (Object.keys(obj.parameter[key]).length !== 0) {
this.selectMode = obj.parameter[key].ttl.toUpperCase()
}
},
},
mounted () {
},
watch: {
},
destroyed () {
},
}
</script>
+2
View File
@@ -3,6 +3,7 @@ import Vuex from 'vuex'
import VuexI18n from 'vuex-i18n' // load vuex i18n module
// import app from './modules/app'
import setting from './modules/setting'
import device from './modules/device'
import taskContent from './modules/task/content'
import state from './state'
@@ -25,6 +26,7 @@ const store = new Vuex.Store({
replay,
spike,
setting,
device,
download,
file,
},
@@ -0,0 +1,4 @@
const controllerActs = {
}
export default controllerActs
@@ -0,0 +1,7 @@
import controllerAct from './controllerAct'
import triggerAct from './triggerAct'
export default {
...controllerAct,
...triggerAct,
}
@@ -0,0 +1,53 @@
import types from '@/store/modules/device/types'
const typePath = types.trigger
const triggerActs = {
/**
* get trigger output channels set
* @param {string} mac
* @return {set}
*/
[typePath.getOutputChannels]: async ({ state, getters, commit, dispatch }, payload) => {
const outputChannels = new Set()
const obj = state.triggerList.find(o => o.mac === payload.mac)
const channelSet = obj.parameter.bitmode.toString(2).split('').reverse()
channelSet.forEach((element, index) => {
if (parseInt(element) > 0) {
outputChannels.add(index)
}
})
return outputChannels
},
/**
* get trigger input channels list
* @param {string} mac
* @return {array}
*/
[typePath.getInputChannels]: async ({ state, getters, commit, dispatch }, payload) => {
const outputChannels = Array.from(await dispatch(typePath.getOutputChannels, { mac: payload.mac }))
const remain = state.allChannels.filter(x => !outputChannels.includes(x))
const obj = state.triggerList.find(o => o.mac === payload.mac)
const inputChannels = []
for (const index in remain) {
const key = 'channel_event_' + index
if (Object.keys(obj.parameter[key]).length !== 0) {
inputChannels.push(index)
}
}
return inputChannels
},
/**
* get trigger active (input + output) channels list
* @param {string} mac
* @return {array}
*/
[typePath.getActiveChannels]: async ({ state, getters, commit, dispatch }, payload) => {
const outputChannels = Array.from(await dispatch(typePath.getOutputChannels, { mac: payload.mac }))
const inputChannels = await dispatch(typePath.getInputChannels, { mac: payload.mac })
const union = [...new Set([...outputChannels, ...inputChannels])]
return union
},
}
export default triggerActs
@@ -0,0 +1,6 @@
import { getField } from 'vuex-map-fields'
export default {
getField,
}
+12
View File
@@ -0,0 +1,12 @@
import actions from './actions'
import getters from './getters'
import mutations from './mutations'
import state from './state'
export default {
namespaced: true,
state: state,
getters: getters,
actions: actions,
mutations: mutations,
}
@@ -0,0 +1,4 @@
const controllerMutations = {
}
export default controllerMutations
@@ -0,0 +1,7 @@
import controllerMut from './controllerMut'
import { updateField } from 'vuex-map-fields'
export default {
...controllerMut,
updateField,
}
+8
View File
@@ -0,0 +1,8 @@
function newState () {
return {
triggerList: [],
allChannels: [0, 1, 2, 3], // trigger channel
}
}
export default newState
+10
View File
@@ -0,0 +1,10 @@
const types = {
trigger: {
getOutputChannels: 'deviceTriggerGetOutputChannels',
getInputChannels: 'deviceTriggerGetInputChannels',
getActiveChannels: 'deviceTriggerGetActiveChannels',
},
}
export default types