const fs = require('fs') const config = require('./config.json') const io = require("socket.io-client") const axios = require('axios') const socket = io(new URL(config.pager.url).origin) const { read } = require('feed-reader') const stateMachine = {} socket.on('msgmgr:event', async (eventType, eventData) => { console.log(eventType, eventData) }) const umlautMapGermany = { '\u00dc': ']', '\u00c4': '[', '\u00d6': "\\", '\u00fc': '}', '\u00e4': '{', '\u00f6': '|', '\u00df': '~', } const umlautMapIntl = { '\u00dc': 'U', '\u00c4': 'A', '\u00d6': 'O', '\u00fc': 'u', '\u00e4': 'a', '\u00f6': 'o', '\u00df': 'ss', } function itnlUmlaute(str) { let umlautMap = umlautMapIntl return str .replace(/[\u00dc|\u00c4|\u00d6][a-z]/g, (a) => { const big = umlautMap[a.slice(0, 1)]; return big.charAt(0) + big.charAt(1).toLowerCase() + a.slice(1); }) .replace(new RegExp('['+Object.keys(umlautMap).join('|')+']',"g"), (a) => umlautMapIntl[a] ); } function replaceUmlaute(str) { let umlautMap = config.germanUmlautSupport ? umlautMapGermany : umlautMapIntl return str .replace(/[\u00dc|\u00c4|\u00d6][a-z]/g, (a) => { const big = umlautMap[a.slice(0, 1)]; return big.charAt(0) + big.charAt(1).toLowerCase() + a.slice(1); }) .replace(new RegExp('['+Object.keys(umlautMap).join('|')+']',"g"), (a) => umlautMap[a] ); } async function sendPage(preset, payload) { console.log(preset, payload) try { await axios.post(new URL(config.pager.url).origin + '/api/message/' + (!!preset ? 'preset' : 'advanced'), Object.assign( !!preset ? { preset } : { ...config.pager.params } // backward compatibility , { payload: payload })) } catch (e) {} } function analyzeCategory(txt) { //console.log('analyzing text', txt) if (txt.indexOf('WINDBOEN')>-1) return 'wind_storm' if (txt.indexOf('STURMBOEN')>-1) return 'wind_storm' if (txt.indexOf('ORKANBOEN')>-1) return 'wind_storm' if (txt.indexOf('STARKREGEN')>-1) return 'rain1' if (txt.indexOf('DAUERREGEN')>-1) return 'rain2' if (txt.indexOf('GEWITTER')>-1) return 'thunderstorm' if (txt.indexOf('SCHNEE')>-1) return 'snow' if (txt.indexOf('FROST')>-1) return 'frost' if (txt.indexOf('GLATTE')>-1) return 'ice' if (txt.indexOf('NEBEL')>-1) return 'fog' return 'none' } function analyzeLevel(txt) { if (txt.indexOf('STUFE 1 VON ')>-1) return 1 if (txt.indexOf('STUFE 2 VON ')>-1) return 2 if (txt.indexOf('STUFE 3 VON ')>-1) return 3 if (txt.indexOf('STUFE 4 VON ')>-1) return 4 return 0 } async function checkDWD() { for (region of config.regions) { if (!region.active) continue try { let rssData = await read('https://wettwarn.de/rss/' + region.dwdID + '.rss') let msg = "" rssData.entries.sort((a,b) => new Date(b.published).valueOf() - new Date(a.published).valueOf()) if (rssData.entries.length > 0) { msg = rssData.entries[0].description const msgCategory = analyzeCategory(itnlUmlaute(msg.toUpperCase())) const msgLevel = analyzeLevel(itnlUmlaute(msg.toUpperCase())) //console.log('type', msgCategory, 'level', msgLevel) const msgLevelTrigger = !!region.levels[msgCategory] ? region.levels[msgCategory] : 0 //console.log(msgLevelTrigger, 'is the trigger level for', msgCategory) if (msgLevel >= msgLevelTrigger) { } else continue // ignore the stuff we want to ignore msg = msg.replace('DWD UNWETTERWARNUNG:', 'DWD:') msg = msg.replace('DWD WETTERWARNUNG:', 'DWD:') msg = msg.replace(' in ', ' ') msg = msg.replace(' von ', '/') msg = msg.indexOf('Quelle:') > -1 ? msg.split('Quelle:')[0] : msg msg = replaceUmlaute(msg) if (!!stateMachine[ region.dwdID ]) { if (stateMachine [ region.dwdID ] != msg) { if (msg.indexOf('Es sind keine Warnungen') > -1) { if (!!region.ignoreEOW) continue } await sendPage( region.preset, msg ) stateMachine [ region.dwdID ] = msg } } else { stateMachine [ region.dwdID ] = msg // if initial state is unknown and we have an alert, send it anyway if (msg.indexOf('Es sind keine Warnungen') == -1) { await sendPage( region.preset, msg ) } } } } catch (e) {console.error(e)} } } function main() { // listen setTimeout(checkDWD, 0) setInterval(checkDWD, 5 * 60 * 1e3) } main() 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')) /** 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.pager)) return res.status(403).json(false) if (!(!!req.body.regions)) 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(3050, '0.0.0.0' || config.host || '127.0.0.1')