Skip to content

Commit

Permalink
ATIS added conditions and blueflash
Browse files Browse the repository at this point in the history
#61
- Added support for extracting wx conditions (precipitation, obscuration etc)
- Added support for blueflash (toggleable in settings)
- Toggleable local ATIS input (in settings)
  • Loading branch information
maxlk96 committed Oct 25, 2024
1 parent 396b5c2 commit afef988
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 42 deletions.
14 changes: 11 additions & 3 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"diff": "^5.2.0",
"moment": "^2.30.1",
"ol": "^9.2.2",
"papaparse": "^5.4.1",
"pinia": "^2.1.7",
"uuid": "^9.0.1",
"vue": "^3.4.21",
Expand Down
148 changes: 110 additions & 38 deletions frontend/src/components/ATIS.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
<div
v-else
class="atis"
:class="changed ? 'flash' : ''"
:class="{ flash: changed && settings.metreportFlash, 'flash-long': changedLong && settings.metreportFlash }"
style="height: 100%"
@click="click"
>
<div class="float-right text-caption text-grey-darken-2">
{{ time }}
</div>
<v-text-field
v-if="settings.enableLocalAtis"
v-model="localAtisInput"
label="Enter local ATIS"
@input="updateLocalAtis"
Expand Down Expand Up @@ -145,24 +146,49 @@ const extractVisibility = (text: string) => {
return `VIS ${visData}`
}
const extractTemperature = (text: string) => {
const match = text.match(/T(?:M)?(-?\d+)/)
if (match) {
const temp = match[1].padStart(2, '0')
return text.includes('TM') ? `TMS${temp}` : `T${temp}`
const extractWeatherConditions = (text: string) => {
const visToCloudRegex = /VIS.*?(?=CLD)/s;
const match = text.match(visToCloudRegex);
if (!match) return "";
const conditionText = match[0];
const conditionRegex = /(RE)?(\+|-|VC)?(MI|BC|PR|DR|BL|SH|TS|FZ)?(DZ|RA|SN|SG|IC|PL|GR|GS|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS){1,3}/g;
const conditions = [];
let conditionMatch;
while ((conditionMatch = conditionRegex.exec(conditionText)) !== null) {
let condition = '';
// Recent
if (conditionMatch[1]) {
condition += conditionMatch[1];
}
// Intensity or proximity
if (conditionMatch[2]) {
condition += conditionMatch[2];
}
// Descriptor
if (conditionMatch[3]) {
condition += conditionMatch[3];
}
// Precipitation, Obscuration, or Other (up to 3)
if (conditionMatch[4]) {
condition += conditionMatch[4];
}
conditions.push(condition);
}
return ''
}
const extractDewpoint = (text: string) => {
const match = text.match(/DP(?:M)?(-?\d+)/)
if (match) {
const dewpoint = match[1].padStart(2, '0')
return text.includes('DPM') ? `DPMS${dewpoint}` : `DP${dewpoint}`
if (conditionText.includes('NSW')) {
conditions.push('NSW');
}
return ''
}
return conditions.join(' ');
}
const extractClouds = (text: string) => {
const cloudRegex = /(FEW|SCT|BKN|OVC)(\d{3})(CB|TCU)?/g;
const vvRegex = /VV(\d{3}|\/{3})/;
Expand Down Expand Up @@ -206,7 +232,7 @@ const extractClouds = (text: string) => {
}
if (vertVisibility) {
return vertVisibility;
return `CLD ${vertVisibility}`;
}
if (specialCloud) {
Expand All @@ -221,6 +247,22 @@ const extractClouds = (text: string) => {
return '';
}
const extractTemperature = (text: string) => {
const match = text.match(/T(\d{2})\//)
if (match) {
return `T${match[1]}`
}
return ''
}
const extractDewpoint = (text: string) => {
const match = text.match(/\/DP(\d{2})/)
if (match) {
return `DP${match[1]}`
}
return ''
}
const formatAtisText = (text: string) => {
if (!text) return ""
Expand All @@ -245,8 +287,7 @@ const formatAtisText = (text: string) => {
const date = extractInfo(/(\d{6}Z)/)
const wind = extractWind(text)
const vis = extractVisibility(text)
//TODO Precipitation/Weather
const precipitation = extractInfo(/(FBL|MOD)\s+(RA|DZ)/)
const conditions = extractWeatherConditions(text)
const clouds = extractClouds(text)
const temperature = extractTemperature(text)
const dewpoint = extractDewpoint(text)
Expand All @@ -265,7 +306,7 @@ WIND ${wind}
${vis}
${precipitation}
${conditions}
${clouds}
${temperature.padEnd(9)}${dewpoint}
Expand All @@ -276,36 +317,64 @@ ${other}
}
const changed = ref(false)
let changeTimeout: any = null
const changedLong = ref(false)
let changeTimeouts: any[] = []
function click() {
if (changeTimeout) clearTimeout(changeTimeout)
changed.value = false
for (const timeout of changeTimeouts) clearTimeout(timeout)
changeTimeouts.splice(0)
changed.value = changedLong.value = false
}
function updateLocalAtis() {
if (localAtisInput.value) {
localAtis.value = {
text: localAtisInput.value.split("\n"),
last_updated: moment().unix()
const firstUpdate = ref(true)
watch([
time,
() => atis.value?.text, // This covers the entire ATIS text, including atisLetter, atisCode, runway, etc.
() => localAtis.value?.text
], (newValues, oldValues) => {
if (firstUpdate.value) {
firstUpdate.value = false
return
}
changed.value = false
if (!settings.metreportFlash) return
for (let i = 0; i < newValues.length; i++) {
if (oldValues[i] && oldValues[i].length > 0 && JSON.stringify(newValues[i]) !== JSON.stringify(oldValues[i])) {
changed.value = true
break
}
} else {
localAtis.value = null
}
}
if (changed.value) {
changeTimeouts.splice(0)
changeTimeouts.push(setTimeout(() => (changed.value = false), 1000))
changeTimeouts.push(setTimeout(() => (changed.value = true), 2000))
changeTimeouts.push(
setTimeout(() => {
changed.value = false
changedLong.value = true
}, 3000)
)
changeTimeouts.push(
setTimeout(() => {
changed.value = false
changedLong.value = false
}, 63000)
)
}
})
watch(atis, (newValue, oldValue) => {
if (oldValue && newValue && !settings.atisFlash) return
changed.value = true
if (changeTimeout) clearTimeout(changeTimeout)
changeTimeout = setTimeout(() => {
changed.value = false
}, 3000)
watch(() => settings.enableLocalAtis, (newValue) => {
if (!newValue) {
localAtisInput.value = ""
localAtis.value = null
}
})
onMounted(() => {
if (!vatsim.data.general) vatsim.fetchData()
})
</script>

<style scoped>
Expand All @@ -314,5 +383,8 @@ onMounted(() => {
color: #ddd;
transition: background-color 0.5s, color 0.5s;
}
.atis.flash-long {
color: #33f;
transition: color 0.5s;
}
</style>

3 changes: 3 additions & 0 deletions frontend/src/stores/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ export const useSettingsStore = defineStore("settings", () => {
const windowSnapping = ref(true)
const metreportFlash = ref(true)
const metsensorFlash = ref(false)
const enableLocalAtis = ref(false)

if ("settings" in localStorage) {
try {
const settings = JSON.parse(localStorage.settings)
if ("windowSnapping" in settings) windowSnapping.value = settings.windowSnapping
if ("metreportFlash" in settings) metreportFlash.value = settings.metreportFlash
if ("metsensorFlash" in settings) metsensorFlash.value = settings.metsensorFlash
if ("enableLocalAtis" in settings) enableLocalAtis.value = settings.enableLocalAtis
} catch (e: any) {
console.error("Failed to parse settings", e)
delete localStorage.settings
Expand All @@ -30,5 +32,6 @@ export const useSettingsStore = defineStore("settings", () => {
windowSnapping,
metreportFlash,
metsensorFlash,
enableLocalAtis,
}
})
3 changes: 2 additions & 1 deletion frontend/src/views/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
<v-container>
<h1>Options</h1>
<v-switch color="white" base-color="grey-darken-1" hide-details label="Window snapping" v-model="settings.windowSnapping" />
<v-switch color="white" base-color="grey-darken-1" hide-details label="METREPORT flash when changed" v-model="settings.metreportFlash" />
<v-switch color="white" base-color="grey-darken-1" hide-details label="METREPORT/ATIS flash when changed" v-model="settings.metreportFlash" />
<v-switch color="white" base-color="grey-darken-1" hide-details label="METSENSOR flash changed values" v-model="settings.metsensorFlash" />
<v-switch color="white" base-color="grey-darken-1" hide-details label="Enable local ATIS input" v-model="settings.enableLocalAtis" />
</v-container>
</v-main>
</template>
Expand Down

0 comments on commit afef988

Please sign in to comment.