2019-07-09 23:51:24 -04:00
|
|
|
<template>
|
|
|
|
<tr :class="{ timedOut, lowVoltage, neverHeard: !status.lastHeard }">
|
2019-07-12 14:10:53 -04:00
|
|
|
<td :title="callsign">{{ tacticalAndOrCall }}</td>
|
2019-07-09 23:51:24 -04:00
|
|
|
<template v-if="status.lastHeard">
|
|
|
|
<td>{{ formatTime(status.lastHeard) }}</td>
|
|
|
|
<td>{{ formatTime(now - status.lastHeard, true) }}</td>
|
2019-07-12 14:36:00 -04:00
|
|
|
<td>{{ formatTime(Math.round(status.avgDelta), true) }}</td>
|
2019-07-13 08:48:50 -04:00
|
|
|
<td>{{ status.lastMicE }}</td>
|
2019-07-09 23:51:24 -04:00
|
|
|
<td>{{ status.lastVoltage || "" }}</td>
|
|
|
|
<td>{{ status.lastTemperature || "" }}</td>
|
2019-07-13 08:48:50 -04:00
|
|
|
<td>{{ status.lastComment }}</td>
|
2019-07-09 23:51:24 -04:00
|
|
|
</template>
|
|
|
|
<template v-else>
|
|
|
|
<td>Never Heard</td>
|
|
|
|
<td>Never Heard</td>
|
|
|
|
<td>Never Heard</td>
|
|
|
|
<td>Never Heard</td>
|
2019-07-12 14:36:00 -04:00
|
|
|
<td>Never Heard</td>
|
2019-07-13 08:48:50 -04:00
|
|
|
<td>Never Heard</td>
|
|
|
|
<td>Never Heard</td>
|
2019-07-09 23:51:24 -04:00
|
|
|
</template>
|
|
|
|
</tr>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import config from "./status_config.yaml";
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: "StationRow",
|
|
|
|
props: { callsign: String, tactical: String, messages: Array, now: Date },
|
|
|
|
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
status: {
|
|
|
|
lastHeard: null,
|
|
|
|
delta: null,
|
|
|
|
lastVoltage: null,
|
|
|
|
lastTemperature: null
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
notify(title, body) {
|
|
|
|
return new Notification(title, { body: body, requireInteraction: true });
|
|
|
|
},
|
|
|
|
|
|
|
|
formatTime(time, isDuration = false) {
|
|
|
|
return new Date(time).toLocaleTimeString(
|
|
|
|
"en-GB",
|
|
|
|
isDuration ? { timeZone: "UTC" } : {}
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
prettyDuration(duration) {
|
|
|
|
let date = new Date(duration);
|
|
|
|
return [
|
|
|
|
...Object.entries({
|
|
|
|
hours: date.getUTCHours(),
|
|
|
|
minutes: date.getUTCMinutes(),
|
|
|
|
seconds: date.getUTCSeconds(),
|
|
|
|
milliseconds: date.getUTCMilliseconds()
|
|
|
|
})
|
|
|
|
]
|
|
|
|
.filter(([suffix, num]) => num > 0)
|
|
|
|
.map(([suffix, num]) => num + " " + suffix)
|
|
|
|
.join(" ");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
messages() {
|
|
|
|
Object.assign(
|
|
|
|
this.status,
|
2019-07-12 14:36:00 -04:00
|
|
|
this.messages.reduce((acc, message, idx, arr) => {
|
2019-07-09 23:51:24 -04:00
|
|
|
acc.lastHeard = message.date.getTime();
|
2019-07-12 14:36:00 -04:00
|
|
|
if (idx === 0) {
|
|
|
|
acc.avgDelta = 0;
|
|
|
|
} else {
|
|
|
|
let delta = message.date.getTime() - arr[idx - 1].date.getTime();
|
|
|
|
acc.avgDelta = (acc.avgDelta * (idx - 1) + delta) / idx;
|
|
|
|
}
|
2019-07-13 08:48:50 -04:00
|
|
|
if ("data" in message) {
|
|
|
|
if ("analog" in message.data) {
|
|
|
|
acc.lastVoltage = message.data.analog[0] / 10;
|
|
|
|
acc.lastTemperature = message.data.analog[1];
|
|
|
|
}
|
2019-07-13 09:07:18 -04:00
|
|
|
acc.lastMicE = message.data.mice || acc.lastMicE;
|
|
|
|
acc.lastComment = message.data.comment || acc.lastComment;
|
2019-07-09 23:51:24 -04:00
|
|
|
}
|
|
|
|
return acc;
|
|
|
|
}, {})
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
lowVoltage(newVal) {
|
|
|
|
if (newVal) {
|
|
|
|
this.notify(
|
2019-07-12 14:10:53 -04:00
|
|
|
`${this.tacticalAndOrCall}'s battery has dropepd below ${config.lowVoltage}V`,
|
2019-07-09 23:51:24 -04:00
|
|
|
`Voltage: ${this.status.lastVoltage}`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
timedOut(newVal) {
|
|
|
|
if (newVal) {
|
|
|
|
this.notify(
|
|
|
|
`${
|
2019-07-12 14:10:53 -04:00
|
|
|
this.tacticalAndOrCall
|
2019-07-09 23:51:24 -04:00
|
|
|
} has not been heard for over ${this.prettyDuration(
|
|
|
|
config.timeoutLength
|
|
|
|
)}!`,
|
|
|
|
`Last Heard: ${this.formatTime(
|
|
|
|
this.status.lastHeard
|
|
|
|
)} (${this.prettyDuration(this.now - this.status.lastHeard)} ago!)`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
computed: {
|
2019-07-12 14:10:53 -04:00
|
|
|
tacticalAndOrCall() {
|
|
|
|
return this.tactical
|
|
|
|
? `${this.tactical} [${this.callsign}]`
|
|
|
|
: this.callsign;
|
2019-07-09 23:51:24 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
timedOut() {
|
|
|
|
if (!this.status.lastHeard) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let nowDelta = new Date(this.now - this.status.lastHeard);
|
|
|
|
return nowDelta.getTime() > config.timeoutLength;
|
|
|
|
},
|
|
|
|
|
|
|
|
lowVoltage() {
|
|
|
|
return (
|
|
|
|
this.status.lastVoltage && this.status.lastVoltage < config.lowVoltage
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
tr.timedOut {
|
|
|
|
background-color: red;
|
|
|
|
}
|
|
|
|
|
|
|
|
tr.lowVoltage {
|
|
|
|
background-color: yellow;
|
|
|
|
}
|
|
|
|
|
|
|
|
tr.neverHeard {
|
|
|
|
background-color: purple;
|
|
|
|
color: #eee;
|
|
|
|
}
|
|
|
|
</style>
|