UNPKG

homebridge-touchwand-jewish-sensors

Version:
303 lines (266 loc) 13.8 kB
"use strict"; let Service, Characteristic, ContactState; module.exports = function (homebridge) { Service = homebridge.hap.Service; Characteristic = homebridge.hap.Characteristic; ContactState = homebridge.hap.Characteristic.ContactSensorState; homebridge.registerAccessory("touchwand-jewish-sensors","JewishCalendar", JewishCalendar); }; class JewishCalendar { constructor (log, config, api) { this.log = log; this.lat = parseFloat(config.latitude); this.long = parseFloat(config.longitude); this.name = config.name; this.il = config.israel; this.sheminiatzeret_in_sukkot = config.sheminiatzeret_in_sukkot; this.candlelighting = config.candlelighting; this.havdalah = config.havdalah; this.sefiratOmerCustom = config.sefiratOmerCustom; this.threeWeeksCustom = config.threeWeeksCustom; this.HeDate = require('he-date'); this.SunCalc = require('suncalc'); this.offset = config.offset; this.services = {}; this.services.Shabbat = new Service.Switch(config.Shabbat, "Shabbat"); this.services.YomTov = new Service.Switch(config.YomTov, "YomTov"); this.services.Kodesh = new Service.Switch(config.Kodesh, "Kodesh"); this.services.RoshHashana = new Service.Switch(config.RoshHashana, "RoshHashana"); this.services.YomKippur = new Service.Switch(config.YomKippur, "YomKippur"); this.services.Sukkot = new Service.Switch(config.Sukkot, "Sukkot"); this.services.SheminiAtzeret = new Service.Switch(config.SheminiAtzeret, "SheminiAtzeret"); this.services.Pesach = new Service.Switch(config.Pesach, "Pesach"); this.services.Shavuot = new Service.Switch(config.Shavuot, "Shavuot"); this.services.Chanukah = new Service.Switch(config.Chanukah, "Chanukah"); this.services.ThreeWeeks = new Service.Switch(config.ThreeWeeks, "ThreeWeeks"); this.services.Omer = new Service.Switch(config.Omer, "Omer"); this.services.SefiratOmer = new Service.Switch(config.SefiratOmer, "SefiratOmer"); this.services.Mourning = new Service.Switch(config.Mourning, "Mourning"); this.updateJewishDay(); //this.updateSensors(); this.updateSwitchs() setTimeout(this.updateLoop.bind(this), 30000); } updateSwitchs(){ this.services.Shabbat.getCharacteristic(this.isShabbat()?Characteristic.On:Characteristic.Off); } updateSensors(){} // updateSensors() { // this.services.Shabbat.getCharacteristic(Characteristic.Switch).setValue(this.isShabbat()); // this.services.YomTov.getCharacteristic(Characteristic.Switch).setValue(this.isYomTov()); // this.services.Kodesh.getCharacteristic(Characteristic.Switch).setValue(this.isKodesh()); // this.services.RoshHashana.getCharacteristic(Characteristic.Switch).setValue(this.isRoshHashana()); // this.services.YomKippur.getCharacteristic(Characteristic.Switch).setValue(this.isYomKippur()); // this.services.Sukkot.getCharacteristic(Characteristic.Switch).setValue(this.isSukkot()); // this.services.SheminiAtzeret.getCharacteristic(Characteristic.Switch).setValue(this.isSheminiAtzeret()); // this.services.Pesach.getCharacteristic(Characteristic.Switch).setValue(this.isPesach()); // this.services.Shavuot.getCharacteristic(Characteristic.Switch).setValue(this.isShavuot()); // this.services.Chanukah.getCharacteristic(Characteristic.Switch).setValue(this.isChanukah()); // this.services.ThreeWeeks.getCharacteristic(Characteristic.Switch).setValue(this.isThreeWeeks()); // this.services.Omer.getCharacteristic(Characteristic.Switch).setValue(this.isOmer()); // this.services.SefiratOmer.getCharacteristic(Characteristic.Switch).setValue(this.isSefiratOmer()); // this.services.Mourning.getCharacteristic(Characteristic.Switch).setValue(this.isMourning()); // } getName(obj, callback) { callback(null, obj.name); } getServices() { var informationService = new Service.AccessoryInformation(); informationService .setCharacteristic(Characteristic.Name, this.name) .setCharacteristic(Characteristic.Manufacturer, "Zeev Mindali") .setCharacteristic(Characteristic.Model, "Jewish Sensors") .setCharacteristic(Characteristic.SerialNumber, "1974") .setCharacteristic(Characteristic.FirmwareRevision, 1974); var services = [ informationService, this.services.Shabbat, this.services.YomTov, this.services.Kodesh, this.services.RoshHashana, this.services.YomKippur, this.services.Sukkot, this.services.SheminiAtzeret, this.services.Pesach, this.services.Shavuot, this.services.Chanukah, this.services.ThreeWeeks, this.services.Omer, this.services.SefiratOmer, this.services.Mourning ]; return services; } updateJewishDay() { this.gDate = new Date(); if ((typeof this.offset !== 'undefined') && (this.offset != 0)) { this.log.debug("Shifting the time by " + this.offset + " minutes."); this.gDate = new Date(this.gDate.getTime() + this.offset * 60000); } this.log.debug("Test date is " + this.gDate.toISOString()); this.hDate = new this.HeDate(this.gDate); // Extremely weird bug in Suncalc has it calculate the wrong times at edges of the day. Workaround is to always check at noon var midday = new Date(this.gDate.getFullYear(), this.gDate.getMonth(), this.gDate.getDate(), 12, 0, 0, 0, 0); // For debugging, track them both this.log.debug("updateJewishDay(): today=" + this.gDate.toISOString()); this.log.debug("updateJewishDay(): midday=" + midday.toISOString()); var suntimes = this.SunCalc.getTimes(midday, this.lat, this.long); this.sunset = suntimes.sunsetStart; this.log.debug("Sunset Tonight: " + this.sunset.toLocaleString()); // Note, this is for programming. In non leap years, Adar1 and Adar2 are BOTH 5. Month is zero indexed. this.hebrewMonths = {'Tishri': 0, 'Heshvan': 1, 'Kislev': 2, 'Tevet': 3, 'Shevat': 4, 'Adar1': 5}; var thisYear = this.hDate.getFullYear(); this.hebrewMonths.Adar2 = new this.HeDate(thisYear + 1, -7).getMonth(); this.hebrewMonths.Nisan = new this.HeDate(thisYear + 1, -6).getMonth(); this.hebrewMonths.Iyar = new this.HeDate(thisYear + 1, -5).getMonth(); this.hebrewMonths.Sivan = new this.HeDate(thisYear + 1, -4).getMonth(); this.hebrewMonths.Tamuz = new this.HeDate(thisYear + 1, -3).getMonth(); this.hebrewMonths.Av = new this.HeDate(thisYear + 1, -2).getMonth(); this.hebrewMonths.Elul = new this.HeDate(thisYear + 1, -1).getMonth(); this.log.debug("This Year's Hebrew Months: "); this.log.debug(this.hebrewMonths); } updateLoop() { var today = new Date(); this.updateJewishDay(); //this.updateSensors(); this.updateSwitchs(); setTimeout(this.updateLoop.bind(this), 30000); } isShabbat() { var day = this.gDate.getDay(); var candletime = new Date(this.sunset); candletime.setMinutes(this.sunset.getMinutes() - this.candlelighting); var havdalahtime = new Date(this.sunset); havdalahtime.setMinutes(this.sunset.getMinutes() + this.havdalah); return (((5 == day) && (this.gDate > candletime)) || ((6 == day) && (this.gDate < havdalahtime))); } isRoshHashana() { // Because of year wraps, if it's Elul 29, we check candle lighting, otherwise, use normal DateRange if ((this.hDate.getMonth() == this.hebrewMonths.Elul)&& this.hDate.getDate () == 29) { var candletime = new Date(this.sunset); candletime.setMinutes(this.sunset.getMinutes() - this.candlelighting); return this.gDate > candletime; } return this._inHebrewHolidayDateRange({month: this.hebrewMonths.Tishri, date: 0}, {month: this.hebrewMonths.Tishri, date: 2}); } isYomKippur() { return this._inHebrewHolidayDateRange({month: this.hebrewMonths.Tishri, date: 9}, {month: this.hebrewMonths.Tishri, date: 10}); } isSukkot() { var begin = {month: this.hebrewMonths.Tishri, date: 14}; var end = (!this.il && this.sheminiatzeret_in_sukkot) ? {month: this.hebrewMonths.Tishri, date: 22} : {month: this.hebrewMonths.Tishri, date: 21}; return this._inHebrewHolidayDateRange(begin, end); } _isSukkotYomTov() { var begin = {month: this.hebrewMonths.Tishri, date: 14}; var end = (this.il) ? {month: this.hebrewMonths.Tishri, date: 15} : {month: this.hebrewMonths.Tishri, date: 16}; return this._inHebrewHolidayDateRange(begin, end); } isSheminiAtzeret() { var begin = {month: this.hebrewMonths.Tishri, date: 21}; var end = (this.il) ? {month: this.hebrewMonths.Tishri, date: 22} : {month: this.hebrewMonths.Tishri, date: 23}; return this._inHebrewHolidayDateRange(begin, end); } isPesach() { var begin = {month: this.hebrewMonths.Nisan, date: 14}; var end = (this.il) ? {month: this.hebrewMonths.Nisan, date: 21} : {month: this.hebrewMonths.Nisan, date: 22}; return this._inHebrewHolidayDateRange(begin, end); } isThreeWeeks() { var begin; // night before Erev 17th of Tamuz if (this.threeWeeksCustom == "Ashkenazi") { begin = {month: this.hebrewMonths.Tamuz, date: 16}; } else if (this.threeWeeksCustom == "Sephardic") { begin = {month: this.hebrewMonths.Tamuz, date: 29}; } var Av9 = new this.HeDate(this.hDate.getFullYear(), this.hebrewMonths.Av, 9); var endDate = (Av9.getDay() == 6) ? 11 : 10; // Includes day after Fast. var end = {month: this.hebrewMonths.Av, date: endDate }; return this._inHebrewHolidayDateRange(begin, end); } _isPesachYomTov() { // Leap years can make Nisan's month number "bounce" so we check for it var begin = {month: this.hebrewMonths.Nisan, date: 14}; var end = (this.il) ? {month: this.hebrewMonths.Nisan, date: 15} : {month: this.hebrewMonths.Nisan, date: 16}; var firstDays = this._inHebrewHolidayDateRange(begin, end); begin = {month: this.hebrewMonths.Nisan, date: 20}; end = (this.il) ? {month: this.hebrewMonths.Nisan, date: 21} : {month: this.hebrewMonths.Nisan, date: 22}; var secondDays = this._inHebrewHolidayDateRange(begin, end); return firstDays || secondDays; } isOmer() { var begin = {month: this.hebrewMonths.Nisan, date: 15}; var end = {month: this.hebrewMonths.Sivan, date: 6}; return this._inHebrewHolidayDateRange(begin, end); } isSefiratOmer() { var begin = false; var end = false; if (this.sefiratOmerCustom == "Ashkenazi") { begin = {month: this.hebrewMonths.Nisan, date: 15}; end = {month: this.hebrewMonths.Iyar, date: 18}; } else if (this.sefiratOmerCustom == "Sephardic") { begin = {month: this.hebrewMonths.Nisan, date: 15}; end = {month: this.hebrewMonths.Iyar, date: 19}; } else if (this.sefiratOmerCustom == "Iyar") { begin = {month: this.hebrewMonths.Nisan, date: 29}; end = {month: this.hebrewMonths.Sivan, date: 3}; } else if (this.sefiratOmerCustom == "Iyar2") { begin = {month: this.hebrewMonths.Iyar, date: 2}; end = {month: this.hebrewMonths.Sivan, date: 5}; } if (begin && end) { return this._inHebrewHolidayDateRange(begin, end); } return false; } isMourning() { return this.isSefiratOmer() || this.isThreeWeeks();} isShavuot() { // Leap years can make Sivan's month number "bounce" so we check for it var begin = {month: this.hebrewMonths.Sivan, date: 5}; var end = (this.il) ? {month: this.hebrewMonths.Sivan, date: 7} : {month: this.hebrewMonths.Sivan, date: 7}; return this._inHebrewHolidayDateRange(begin, end); } isYomTov() { var holidays = this.isRoshHashana() || this.isYomKippur() || this._isSukkotYomTov() || this.isSheminiAtzeret() || this._isPesachYomTov() || this.isShavuot(); return holidays; } isKodesh() { return (this.isShabbat() || this.isYomTov()); } isChanukah() { var ChanukahEnd = new this.HeDate(this.hDate.getFullYear(), 2, 32); var begin = {month: this.hebrewMonths.Kislev, date: 24 }; var end = {month: ChanukahEnd.getMonth(), date: ChanukahEnd.getDate() }; return this._inHebrewHolidayDateRange(begin, end); } _inHebrewHolidayDateRange(erev, end) { // Assumes that all ranges are within the same Hebraic year. // We COULD support wrap arounds, but it is only needed for Rosh Hashana // Handled there as a special case rule var candletime = new Date(this.sunset); candletime.setMinutes(this.sunset.getMinutes() - this.candlelighting); var havdalahtime = new Date(this.sunset); havdalahtime.setMinutes(this.sunset.getMinutes() + this.havdalah); var todayHebrewMonth = this.hDate.getMonth(); var todayHebrewDate = this.hDate.getDate(); // Date should be in the format {month, date} if ((todayHebrewMonth == erev.month) && (todayHebrewDate == erev.date)) { // First Day -- true after sunset return (this.gDate > candletime); } else if ((todayHebrewMonth == end.month) && (todayHebrewDate == end.date)) { // Last Day -- true until sunset return (this.gDate < havdalahtime); } else if ( ((todayHebrewMonth > erev.month) || (todayHebrewMonth == erev.month && todayHebrewDate > erev.date)) && ((todayHebrewMonth < end.month) || (todayHebrewMonth == end.month && todayHebrewDate < end.date))) { return true; } else { // Not in the middle return false; } } }