first commit

master
cheetah.cat 5 months ago
commit 8967f6c097

@ -0,0 +1,23 @@
{
"pager": {
"url": "http://127.0.0.1:3000/api/message/advanced"
},
"alarms": [
{
"name": "Testalarm",
"preset": "18ccbeedf26",
"alarmSchedulingMode": "weekly",
"alarmTime": "12:05",
"callsign": "EDDM",
"weekDay": {
"0": false,
"1": false,
"2": false,
"3": false,
"4": true,
"5": false,
"6": true
}
}
]
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,204 @@
<!DOCTYPE html>
<html>
<head>
<title>METAR Configuration</title>
<!-- <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"> -->
<link href="/css/materialdesignicons.min.css" rel="stylesheet">
<link href="/css/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
<v-app>
<v-app-bar app>
<v-toolbar-title>METAR Configuration</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn color="success" @click="storeConfig()">Store & Restart</v-btn>
<v-checkbox label="Expert Mode" v-model="EXPERTMODE"></v-checkbox>
</v-app-bar>
<v-content>
<v-form>
<v-tabs v-model="configTab" next-icon="mdi-arrow-right-bold-box-outline"
prev-icon="mdi-arrow-left-bold-box-outline" show-arrows>
<v-tabs-slider></v-tabs-slider>
<v-tab key="testAlarms">METAR Notifications</v-tab>
<v-tab v-show="EXPERTMODE" key="notificationConfig">Notification Configuration</v-tab>
</v-tabs>
<v-tabs-items v-model="configTab">
<v-tab-item key="testAlarms">
<v-container>
<p>Targets:</p>
<v-row>
<v-btn color="primary" fab dark small icon @click="addAlarm()">
<v-icon>mdi-plus</v-icon>
</v-btn>
</v-row>
<v-row v-for="(alarmConfig, index) in configData.alarms" :key="alarmConfig._id">
<v-card>
<v-col cols="12" sm="12" md="12">
<v-btn color="error" dark small fab @click="configData.alarms.splice(index, 1)" icon>
<v-icon>mdi-delete</v-icon>
</v-btn>
</v-col>
<v-col cols="12" sm="12" md="12">
<v-col>
<v-row>
<v-select :items="alarmSchedulingMode" v-model="alarmConfig.alarmSchedulingMode"
item-text="k" item-value="v" label="Scheduling Mode"></v-select>
<v-text-field v-model="alarmConfig.alarmTime" type="time" label="Time"></v-text-field>
</v-row>
<v-row cols="3" sm="3" md="3" v-show="alarmConfig.alarmSchedulingMode == 'weekly'">
<v-checkbox v-for="(WN, index) of weekDays" v-model="alarmConfig.weekDay[ index ]" :label="WN"></v-checkbox>
</v-row>
<v-row cols="3" sm="3" md="3" v-show="alarmConfig.alarmSchedulingMode == 'monthlyFirstOccWeekday'">
<v-select :items="weekDaysSelect" v-model="alarmConfig.firstOccWeekday" label="First Occurance of this Weekday"></v-select>
</v-row>
<v-row cols="3" sm="3" md="3" v-show="alarmConfig.alarmSchedulingMode == 'monthlyAtSpecificDate'">
<v-text-field v-model="alarmConfig.specificWeekday" label="Specific Date (xx-MM-YYYY)"></v-text-field>
</v-row>
</v-col>
<hr/>
</v-col>
<v-row>
<v-col cols="6" sm="6" md="6">
<v-text-field v-model="alarmConfig.name" label="Name"></v-text-field>
<v-autocomplete
v-model="alarmConfig.preset"
:items="presetSearchItems"
:loading="!presetSearchItems.length > 0"
color="white"
hide-no-data
dense
label="Profile"
placeholder="Start typing to Search"
prepend-icon="mdi-database-search"
></v-autocomplete>
</v-col>
<v-col cols="6" sm="6" md="6">
<v-text-field v-model="alarmConfig.callsign" label="CALLSIGN"></v-text-field>
</v-col>
<v-col>
</v-col>
</v-row>
</v-card>
</v-row>
</v-container>
</v-tab-item>
<v-tab-item key="notificationConfig">
<v-container>
<b>Routing Paramters:</b>
<v-row>
<v-col cols="12" sm="12" md="6">
<v-text-field label="Daemon Endpoint URL" v-model="configData.pager.url">
</v-text-field>
</v-col>
</v-row>
</v-container>
</v-tab-item>
</v-tabs-items>
</v-form>
</v-content>
</v-app>
</div>
<script src="/js/moment-with-locales.min.js"></script>
<script src="/js/vue/vue.js"></script>
<script src="/js/vue/vuetify.js"></script>
<script src="/js/vue/vue-resource_1.5.1.js"></script>
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
http: { root: '/' },
data() {
const weekDays = [
'Monday','Tuesday','Wednesday','Thursday','Friday','Saturday', 'Sunday'
]
return {
EXPERTMODE: false,
configTab: null,
alarmSchedulingMode: [
{ k: 'Weekly', v: 'weekly' },
{ k: 'Monthly at first occurance of a specific weekday', v: 'monthlyFirstOccWeekday' },
{ k: 'Monthly at specific date', v: 'monthlyAtSpecificDate' },
],
weekDays,
weekDaysSelect: weekDays.map((val,ind) => { return { value: ind, text: val } }),
configData: {
"bottoken": "",
"pager": {
"url": "",
},
"menuSupport": false,
"deliveryModes": []
},
presetSearchItems: [],
}
},
created() {
this.loadPresets()
this.loadConfig()
},
methods: {
loadPresets() {
this.$http.get(window.location.pathname + 'api/deliveryPresets')
.then(response => {
this.presetSearchItems = response.body.map(x => { return {
text: x.name,
value: x.key,
}})
}, response => {
})
},
loadConfig() {
this.$http.get(window.location.pathname + 'config').then(response => {
const newConfig = response.body
newConfig.alarms = newConfig.alarms.map((x) => {
x._id = btoa(JSON.stringify(x))
return x
})
this.configData = newConfig
}, response => {
})
},
storeConfig() {
const storeConfig = JSON.parse(JSON.stringify(this.configData))
storeConfig.alarms = storeConfig.alarms.map(a=> {
delete a._id
return a
})
this.$http.post(window.location.pathname + 'config', storeConfig)
.then(response => {})
.then(this.$http.post(window.location.pathname + 'restart'))
.then(() => {
document.body.style = 'display:none'
setTimeout(() => window.location.reload(), 1e3)
})
},
addAlarm() {
this.configData.alarms.push({
name: "Target 1",
preset: null,
alarmSchedulingMode: "weekly",
alarmTime: "13:37",
callsign: "EDDM",
weekDay: {
"0": true,
"1": true,
"2": true,
"3": true,
"4": true,
"5": true,
"6": true
},
})
},
}
})
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,97 @@
const config = require('./config.json')
const axios = require('axios')
const fs = require('fs')
const moment = require('moment')
moment.locale('yes', {
week : {
dow : 1
}
})
const express = require('express')
const appConfig = express()
appConfig.use(express.json({ limit: '1mb' }))
appConfig.use(express.static('html'))
appConfig.use(express.static(__dirname + '/node_modules/@mdi/font'))
async function minuteCheck() {
let timeRN = moment()
//console.log('timeRN', timeRN.format("HH:mm"))
for (let alarm of config.alarms) {
let alarmTime = moment()
.hours(+alarm.alarmTime.split(':') [ 0 ])
.minutes(+alarm.alarmTime.split(':') [ 1 ])
let secDiff = alarmTime.diff(timeRN, 'seconds')
//
//console.log(alarmTime.format("HH:mm"), secDiff)
if (alarmTime.format("HH:mm") == timeRN.format("HH:mm")) {
//console.log("TRIGGER", alarm.alarmSchedulingMode)
let alarmTrigger = false
switch (alarm.alarmSchedulingMode) {
case 'monthlyAtSpecificDate':
alarmTrigger = (timeRN.date() == alarmTime.specificWeekday)
break;
case 'monthlyFirstOccWeekday':
// wish Date = alarmTime.firstOccWeekday
let thisMonthFirstWeekDayOccurance = -1
let monthFirstDay = moment().startOf('month')
while (monthFirstDay.weekday() != alarm.firstOccWeekday) monthFirstDay.add(1, 'day')
thisMonthFirstWeekDayOccurance = monthFirstDay.date()
//console.log(monthFirstDay.date(), monthFirstDay.weekday())
//console.log('monthly first occurance for', alarm.firstOccWeekday, 'is', thisMonthFirstWeekDayOccurance)
alarmTrigger = (timeRN.date() == thisMonthFirstWeekDayOccurance)
break;
case 'weekly':
for (let weekDayKey of Object.keys(alarm.weekDay)) {
//console.log(weekDayKey, alarm.weekDay)
if (+weekDayKey === +timeRN.weekday()) {
//console.log('weekday match', 'result is', alarm.weekDay[weekDayKey] )
alarmTrigger = alarm.weekDay[weekDayKey]
break;
}
}
break;
}
if (alarmTrigger === true) {
let eddmWeather = await axios.get(`https://aviationweather.gov/cgi-bin/data/metar.php?ids=${ alarm.callsign }&hours=0&order=id%2C-obs&sep=true`)
console.log(eddmWeather.data)
await axios.post(new URL(config.pager.url).origin + '/api/message/' + (!!alarm.preset ? 'preset' : 'advanced'), Object.assign( !!alarm.preset
? { preset: alarm.preset }
: { ...alarm.params } // backward compatibility
, { payload: eddmWeather.data }))
}
}
}
}
async function main() {
let now = moment()
await minuteCheck()
setTimeout(() => setInterval(minuteCheck, 60e3), now.diff(moment().add(1, 'minute'), 'seconds') * 1e3 + 5e3)
}
main()
/** CONFIG Routes */
appConfig.get('/config', async (req, res) => {
return res.json(JSON.parse(fs.readFileSync('config.json')))
})
appConfig.get('/api/deliveryPresets', async (req, res) => {
const presets = await axios.get(new URL(config.pager.url).origin + '/api/deliveryPresets')
return res.json(presets.data)
})
appConfig.post('/config', async (req, res) => {
if (!(!!req.body.alarms)) return res.status(403).json(false)
if (!(!!req.body.pager)) return res.status(403).json(false)
console.log(req.body)
fs.writeFileSync('config.json', JSON.stringify(req.body, null, "\t"))
return res.json(true)
})
appConfig.post('/restart', (req, res) => {
process.exit(1)
})
appConfig.listen(3110, '0.0.0.0' || config.host || '127.0.0.1')

1159
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,8 @@
{
"dependencies": {
"@mdi/font": "^7.0.96",
"axios": "^1.2.0",
"express": "^4.18.2",
"moment": "^2.29.4"
}
}
Loading…
Cancel
Save