UNPKG

@yachteye/signalk-makkah-plugin

Version:
336 lines (335 loc) 18.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const SunAndPrayTime_1 = require("./SunAndPrayTime"); const trigonometric_1 = require("./trigonometric"); /** * Makkah prayer times Plugin. * @param {*} app The SignalK app. * @returns The plugin object. */ module.exports = (app) => { const plugin = { id: 'signalk-makkah-plugin', name: 'Add Salah and Sun times to the SignalK graph', restartPlugin: null, hourTimeout: null, navigationInterval: null, /** * Start the plugin. * @param {*} settings the configuration data entered via the Plugin Config screen. * @param {*} restartPlugin a function that can be called by the plugin to restart itself. */ start: (settings, restartPlugin) => { app.debug(`${plugin.id} starting...`); plugin.restartPlugin = restartPlugin; try { plugin.meta(settings); plugin.navigationInterval = setInterval(plugin.updateNavigationData, settings.interval * 1000); const calculator = new SunAndPrayTime_1.SunAndPrayTimeCalculator(); calculator.setMethod(settings.method); calculator.numIterations = 2; setTimeout(() => { plugin.work(settings, calculator); }, 45 * 1000); plugin.hourTimeout = plugin.callAfterEveryFullHour(plugin.work.bind(null, settings, calculator)); app.setPluginStatus(`Started (method=${settings.method}, calculation interval=${settings.interval} (seconds)).`); } catch (err) { app.error(`error: ${err === null || err === void 0 ? void 0 : err.message}`); app.setPluginError(`Error in start(): ${err === null || err === void 0 ? void 0 : err.message}`); } }, /** * Stop the plugin. */ stop: () => { if (plugin.hourTimeout) { clearTimeout(plugin.hourTimeout); plugin.hourTimeout = null; } if (plugin.navigationInterval) { clearInterval(plugin.navigationInterval); plugin.navigationInterval = null; } app.setPluginStatus(`Stopped.`); }, work: (settings, calculator) => { try { const now = new Date(); const position = app.getSelfPath('navigation.position'); const dateTime = app.getSelfPath('navigation.datetime'); const tzOffsetData = app.getSelfPath('environment.time.timezoneOffset'); const latLon = plugin.getPosition(position); if (latLon !== null && dateTime !== undefined && dateTime.value) { let tzHourOffset = 0; if (tzOffsetData !== undefined && tzOffsetData.value && typeof tzOffsetData.value === 'number') { tzHourOffset = tzOffsetData.value / 60 / 60; } else { app.debug(`No time zone information available: '${JSON.stringify(tzOffsetData)}'.`); } // Calculate the local date. const utcDateTime = new Date(dateTime.value); const localDateTime = new Date(utcDateTime.getTime() + tzHourOffset * 60 * 60 * 1000); app.debug(`Local time is ${localDateTime.getUTCHours()}:${localDateTime.getUTCMinutes()}, UTC time is ${utcDateTime.getUTCHours()}:${utcDateTime.getUTCMinutes()}, UTC day=${localDateTime.getUTCDate()}, time zone=${tzHourOffset.toFixed(2)} decimal hours`); const prayerTimes = calculator.getDatePrayerTimes(localDateTime.getUTCFullYear(), localDateTime.getUTCMonth() + 1, localDateTime.getUTCDate(), latLon.latitude, latLon.longitude, tzHourOffset); const deltaSalah = { context: 'vessels.self', updates: [{ source: { label: `plugin.id` }, timestamp: now.toISOString(), values: [{ path: settings.signalKPath, value: { fajr: prayerTimes.fajr, dhuhr: prayerTimes.dhuhr, asr: prayerTimes.asr, maghrib: prayerTimes.maghrib, isha: prayerTimes.isha, sunrise: prayerTimes.sunrise, sunset: prayerTimes.sunset, // imsak: prayerTimes.imsak, } }], }], }; app.handleMessage(plugin.id, deltaSalah); const localHours = localDateTime.getUTCHours() + (localDateTime.getUTCMinutes() / 60); const result = calculator.GetSunTimes(localDateTime.getUTCFullYear(), localDateTime.getUTCMonth() + 1, localDateTime.getUTCDate(), latLon.latitude, latLon.longitude, tzHourOffset); // Compute times for tomorrow, and correct the result for times that have already passed. localDateTime.setUTCDate(localDateTime.getUTCDate() + 1); const tomorrow = calculator.GetSunTimes(localDateTime.getUTCFullYear(), localDateTime.getUTCMonth() + 1, localDateTime.getUTCDate(), latLon.latitude, latLon.longitude, tzHourOffset); if (result.sunrise !== null && result.sunrise <= localHours && tomorrow.sunrise !== null) { result.sunrise = tomorrow.sunrise; } if (result.sunset !== null && result.sunset <= localHours && tomorrow.sunset !== null) { result.sunset = tomorrow.sunset; } if (result.civicTwilightStart !== null && result.civicTwilightStart <= localHours && tomorrow.civicTwilightStart !== null) { result.civicTwilightStart = tomorrow.civicTwilightStart; } if (result.civicTwilightEnd !== null && result.civicTwilightEnd <= localHours && tomorrow.civicTwilightEnd !== null) { result.civicTwilightEnd = tomorrow.civicTwilightEnd; } const deltaSun = { context: 'vessels.self', updates: [{ source: { label: `plugin.id` }, timestamp: now.toISOString(), values: [{ path: 'resources.astronomical.sunTimes', value: { sunrise: result.sunrise === null ? '' : calculator.floatToTime24(result.sunrise), sunset: result.sunset === null ? '' : calculator.floatToTime24(result.sunset), civicTwilightStart: result.civicTwilightStart === null ? '' : calculator.floatToTime24(result.civicTwilightStart), civicTwilightEnd: result.civicTwilightEnd === null ? '' : calculator.floatToTime24(result.civicTwilightEnd), } }], }], }; app.handleMessage(plugin.id, deltaSun); app.setPluginStatus(`Successfully calculated Salah/Sun times at ${now.toISOString()}.`); app.debug(`Calculated Salah/Sun times for (lat=${latLon.latitude.toFixed(5)}, lon=${latLon.longitude.toFixed(5)}), tz=${tzHourOffset.toFixed(2)} decimal hours.`); } else { app.setPluginStatus(`No position and/or dateTime data available at ${now.toISOString()}.`); app.debug(`No position (${JSON.stringify(position)}) and/or dateTime (${JSON.stringify(dateTime)}) data available.`); } } catch (err) { app.error(`error: ${err === null || err === void 0 ? void 0 : err.message}`); app.setPluginError(`Error calculating Salah/Sun times: ${err === null || err === void 0 ? void 0 : err.message}`); } }, updateNavigationData: () => { // Values taken from https://en.wikipedia.org/wiki/Kaaba const MakkahLatitude = 21.4225; const MakkahLongitude = 39.8262; try { const now = new Date(); const position = app.getSelfPath('navigation.position'); const latLon = plugin.getPosition(position); if (latLon !== null) { const bearing = (0, trigonometric_1.bearingTo)(latLon.latitude, latLon.longitude, MakkahLatitude, MakkahLongitude); const distance = (0, trigonometric_1.distanceBetweenMeters)(latLon.latitude, latLon.longitude, MakkahLatitude, MakkahLongitude); const delta = { context: 'vessels.self', updates: [{ source: { label: `plugin.id` }, timestamp: now.toISOString(), values: [ { path: 'navigation.bearingToMakkah', value: (0, trigonometric_1.degreeToRadian)(bearing), }, { path: 'navigation.distanceToMakkah', value: Math.round(distance), }, ], }], }; app.handleMessage(plugin.id, delta); app.setPluginStatus(`Calculated distance and direction to Makkah at ${now.toISOString()}.`); } else { app.setPluginStatus(`No position data available at ${now.toISOString()}.`); app.debug(`No position (${JSON.stringify(position)}) data available.`); } } catch (err) { app.error(`error: ${err === null || err === void 0 ? void 0 : err.message}`); app.setPluginError(`Error calculating data: ${err === null || err === void 0 ? void 0 : err.message}`); } }, callAfterEveryFullHour: (functionToCall) => { const now = new Date(); const nextHour = new Date(); nextHour.setHours(nextHour.getHours() + 1, 1, 0, 0); const differenceMs = nextHour.getTime() - now.getTime(); return setTimeout(() => { // Run it. functionToCall(); // Schedule next run. plugin.hourTimeout = plugin.callAfterEveryFullHour(functionToCall); }, differenceMs); }, getPosition: (skData) => { if (skData !== undefined && skData !== null && skData.value && typeof skData.value.latitude === 'number' && typeof skData.value.longitude === 'number') { return { latitude: skData.value.latitude, longitude: skData.value.longitude }; } return null; }, meta: (settings) => { const metaDelta = { context: "vessels.self", updates: [ { timestamp: new Date().toISOString(), meta: [ { path: "navigation.distanceToMakkah", value: { units: "m", description: "Distance to Makkah", displayName: "Distance to Makkah", } }, { path: "navigation.bearingToMakkah", value: { units: "rad", description: "Bearing/Direction to Makkah", displayName: "Bearing/Direction to Makkah", } }, { path: settings.signalKPath, value: { description: "The Salah/Prayer times of today, in 'hh:mm' format", displayName: "The Salah/Prayer times of today", properties: { fajr: { type: "string", description: "The local time of today's Fajr", example: "06:55", }, dhuhr: { type: "string", description: "The local time of today's Dhuhr", example: "13:46", }, asr: { type: "string", description: "The local time of today's Asr", example: "16:35", }, maghrib: { type: "string", description: "The local time of today's Maghrib", example: "19:01", }, isha: { type: "string", description: "The local time of today's Isha", example: "20:32", }, sunrise: { type: "string", description: "The local time of today's sunrise", example: "08:31", }, sunset: { type: "string", description: "The local time of today's sunset", example: "19:01", }, // imsak: { // type: "string", // description: "The local time of today's Imsak", // example: "06:45", // }, }, } }, { path: 'resources.astronomical.sunTimes', value: { description: "The next Sun times (sunrise, sunset, etc.), in 'hh:mm' format", displayName: "The next Sun times", properties: { sunrise: { type: "string", description: "The local time of the next sunrise", example: "08:30", }, sunset: { type: "string", description: "The local time of the next sunset", example: "19:01", }, civicTwilightStart: { type: "string", description: "The local time of the next civic twilight start", example: "08:00", }, civicTwilightEnd: { type: "string", description: "The local time of the next civic twilight end", example: "19:31", }, }, } }, ] } ] }; app.handleMessage(plugin.id, metaDelta); }, schema: () => { return { type: 'object', required: [], properties: { interval: { type: 'number', title: 'Interval to calculate the Makkah distance/direction (seconds)', default: 50, }, signalKPath: { type: 'string', title: 'The SignalK path to use.', default: 'resources.astronomical.salahTimes', }, method: { type: 'string', title: 'The calculation method: MWL, ISNA, Egypt, Makkah, Karachi, Tehran or Jafari.', default: 'MWL', }, } }; }, }; return plugin; };