afify / azan (public) (License: MIT) (since 2020-03-08) (hash sha1)
azan is a simple muslim prayers notifier for unix-like systems.
List of commits:
Subject Hash Author Date (UTC)
[feat] Self Calcutation 1be712f454adda33c8a182a4478a3abf5dba6745 Hassan Afify 2019-09-17 08:11:15
[init] Initial Commit 2654768d0412e07cf7aa4b78a41b125aeceab82e Hassan Afify 2019-09-04 01:44:23
Commit 1be712f454adda33c8a182a4478a3abf5dba6745 - [feat] Self Calcutation
- Replace old way: sending get request to api with self Calcutation
- get equations from: Wikipedia, PrayTimes.org & others

* Current status
- set configuration in config.h
- get fajr, duhr, asr, maghrib, isha, sunrise
- for each prayer return today's time_t
Author: Hassan Afify
Author date (UTC): 2019-09-17 08:11
Committer name: Hassan Afify
Committer date (UTC): 2019-09-18 05:13
Parent(s): 2654768d0412e07cf7aa4b78a41b125aeceab82e
Signing key: 0F6CD1196B2A5658
Tree: 72e27c401c912e978461b88a82944656bf7aef38
File Lines added Lines deleted
Makefile 12 5
TODO 0 9
azan.c 250 178
azan.h 44 5
config.h 27 2
File Makefile changed (mode: 100644) (index caf9556..718f9ed)
1 1 # azan # azan
2 2 # See LICENSE file for copyright and license details. # See LICENSE file for copyright and license details.
3 .POSIX:
3 # .POSIX:
4 # SRC = drw.c dwm.c util.c
5 # OBJ = ${SRC:.c=.o}
4 6
5 7 SRC = azan.c SRC = azan.c
6 8 CC = gcc CC = gcc
7 9 TARGET= azan TARGET= azan
8 IFLAGS= /usr/local/include/
9 LDFLAGS= /usr/local/lib -lcurl -ljson-c
10 STD= -std=c99
11 WARN= -Wall -Wextra -pedantic
12 CFLAGS = ${STD} ${WARN}
13 LIBS= -lm -ljson-c
10 14
11 15 all: all:
12 $(CC) $(SRC) -o $(TARGET) -I $(IFLAGS) -L $(LDFLAGS) -Wall -Wextra -pedantic
16 $(CC) $(SRC) $(CFLAGS) -o $(TARGET) $(LIBS)
13 17
14 18 clean: clean:
15 rm $(TARGET)
19 rm $(TARGET) /tmp/azan_*
16 20
17 21 install: azan install: azan
18 22 cp -f azan /bin cp -f azan /bin
 
... ... install: azan
21 25 uninstall: uninstall:
22 26 rm -f /bin/azan rm -f /bin/azan
23 27
28 splint:
29 splint $(SRC)
30
24 31 .PHONY: all clean install uninstall .PHONY: all clean install uninstall
File TODO deleted (index bd4cfc3..0000000)
1 This Stage:
2 -----------
3 - replace json lib.
4 - fix splint warnings
5 - check functions return int with < 0
6
7 Next Stages:
8 ------------
9 - arg options (print today prayer times with notify-send)
File azan.c changed (mode: 100644) (index 5cccd7d..bf3874b)
1 1 /* See LICENSE file for copyright and license details. /* See LICENSE file for copyright and license details.
2 *
2 3 * Azan is simple Muslim prayers notifier. * Azan is simple Muslim prayers notifier.
3 4 * print next pray left duration. * print next pray left duration.
4 *
5 * use curl lib to make a get request to azan api
6 * save json file in /tmp dir
7 * each time app runs check if cache file exists if not make get request
8 *
9 * read the cache file, get next pray, print left duration %h:%m
10 * send notification if left duration = 0 minutes
11 *
12 * this app should run each 59s
13 5 */ */
14 6
15 7 #include <stdio.h> #include <stdio.h>
16 8 #include <time.h> #include <time.h>
9 #include <math.h>
17 10 #include <string.h> #include <string.h>
18 #include <sys/stat.h>
19 #include <curl/curl.h>
20 #include <json-c/json.h>
21 11
22 12 #include "azan.h" #include "azan.h"
23 13 #include "config.h" #include "config.h"
24 14
25 static int
26 file_exist(char *filename)
27 {
28 struct stat buffer;
29 return (stat(filename, &buffer) == 0);
30 }
31
32 static void
33 get_page(const char* url, const char* file_name)
34 {
35
36 // Check connection
37 CURL *curl = curl_easy_init();
38 if(curl) {
39 CURLcode ret;
40 curl_easy_setopt(curl, CURLOPT_URL, "https://google.com/");
41 // curl_easy_setopt(curl, CURLOPT_URL, "test a failed connection");
42 curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
43 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 2L);
44 ret = curl_easy_perform(curl);
45
46 // If Connected
47 if(ret == CURLE_OK) {
48 CURL* easyhandle = curl_easy_init();
49 curl_easy_setopt(easyhandle, CURLOPT_URL, url);
50 FILE* file = fopen(file_name, "w");
51 curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, file) ;
52 curl_easy_perform(easyhandle);
53 curl_easy_cleanup(easyhandle);
54 fclose(file);
55 }
56
57 // If Not Connected
58 else{
59 printf("not connected\n");
60 }
15 static time_t
16 convert_today_double_to_timet(double event_time)
17 {
18 /* Convert to hour min */
19 double hours = floor(event_time);
20 double minutes = round((event_time - hours) * 60.0);
21
22 time_t now ;
23 time_t converted;
24 (void) time(&now);
25 struct tm tmnow = *localtime(&now);
26 tmnow.tm_hour = (int)hours;
27 tmnow.tm_min = (int)minutes;
28 tmnow.tm_sec = 0;
29 tmnow.tm_mday = tmnow.tm_mday;
30 tmnow.tm_mon = tmnow.tm_mon;
31 tmnow.tm_year = tmnow.tm_year;
32 converted = mktime(&tmnow);
33 /* TEST */
34 //printf("Diff = %f\n", difftime(converted, now));
35 //printf("duhr = %.2f %.2f\n", hours, minutes);
36 return converted;
37 }
38
39 static double
40 convert_gregorian_to_julian(int year, int month, int day)
41 {
42 if(month <= 2){
43 year -= 1;
44 month += 12;
61 45 } }
46 double A = floor((double)year / 100);
47 double B = 2 - A + floor(A / 4);
48 double result = floor(365.25 * ((double)year + 4716)) +
49 floor(30.6001 * ((double)month + 1)) +
50 (double)day + B - 1524.5;
51 return result;
62 52 } }
63 53
64 static void
65 print_next_pray(time_t t, char *json_file)
54 static double
55 convert_degrees_to_radians(const double x)
66 56 { {
57 return ((x) * MI_PI) / 180.0;
58 }
67 59
68 /* this fuction get as argument a json file
69 opens it and find pray times data
70 create a local array to store data
71 assign data to array
60 static double
61 convert_radians_to_degrees(const double x)
62 {
63 return ((x) * 180.0) / MI_PI;
64 }
72 65
73 TODO:
74 1- return values as time type
75 2- pass an array insted of creating local one and no return
76 */
66 static double
67 normalize(const double x, const double N)
68 {
69 // Normalizes the given value x to be within the range [0,N]
70 double n;
71 // assert(N > 0.0);
72 n = x - (N * floor( x / N ));
73 // assert(n <= N);
74 return n;
75 }
77 76
78 // Parse the json file
79 FILE *fp;
80 char buffer[2048];
81
82 fp = fopen(json_file,"r");
83 fread(buffer, 2048, 1, fp);
84 fclose(fp);
85
86 struct json_object *parsed_json;
87 struct json_object *data;
88 struct json_object *timings;
89
90 struct json_object *date;
91 struct json_object *json_hijri;
92 struct json_object *json_date;
93
94 // typedef struct {
95 // const struct json_object *json_pray;
96 // const char *string_pray;
97 // const unsigned int int_pray;
98 // const time_t time_pray;
99 // }PrayTime;
100
101 struct json_object *json_pray[5];
102 const char *array_string_pray[5];
103 int array_array_int_pray[5][2];
104 time_t array_time_pray[6];
105 char array_char_pray_name[6] = {'F','D','A','M','I','F'};
106
107 parsed_json = json_tokener_parse(buffer);
108 json_object_object_get_ex(parsed_json, "data" , &data);
109 json_object_object_get_ex(data, "timings", &timings);
110
111 json_object_object_get_ex(data, "date", &date);
112 json_object_object_get_ex(date, "hijri", &json_hijri);
113 json_object_object_get_ex(json_hijri, "date", &json_date);
114
115 // Hijri date
116 const char *hijri = json_object_get_string(json_date);
117
118 json_object_object_get_ex(timings, "Fajr", &json_pray[0]);
119 json_object_object_get_ex(timings, "Dhuhr", &json_pray[1]);
120 json_object_object_get_ex(timings, "Asr", &json_pray[2]);
121 json_object_object_get_ex(timings, "Maghrib", &json_pray[3]);
122 json_object_object_get_ex(timings, "Isha", &json_pray[4]);
123
124 // Handel time and duration
125 // struct tm current_time = *localtime(&t);
126 struct tm dt = *localtime(&t);
127
128 for(int i = 0; i < 5; i++){
129 // Create array of strings from the json object
130 array_string_pray[i] = json_object_get_string(json_pray[i]),
131
132 // Remove : from string parsed from json file
133 // Add to pray_int array
134 sscanf(array_string_pray[i], "%d:%d",
135 &array_array_int_pray[i][0], &array_array_int_pray[i][1]);
136
137 // Change the hours and minutes from int array to time type
138 dt.tm_hour = array_array_int_pray[i][0];
139 dt.tm_min = array_array_int_pray[i][1];
140 array_time_pray[i] = mktime(&dt);
141 };
142
143 // Create next fajr
144 dt.tm_mday = dt.tm_mday+1;
145 dt.tm_hour = array_array_int_pray[0][0];
146 dt.tm_min = array_array_int_pray[0][1];
147 array_time_pray[5] = mktime(&dt);
148
149 for(int i=0; i<6; i++){
150 if(t == array_time_pray[i]){
151 printf("%*.*s 00:00\n", 5, 5, hijri);
152 char command[100], msg[100];
153 strcpy(command,"notify-send ");
154 strcpy(msg,"\"Azan\"");
155 strcat(command,msg);
156 (void) system(command);
157 break;
77 static double
78 get_equation_time(const unsigned long jdn, double *D)
79 {
80 double d; /* Julian Day Number from 1 January 2000 */
81 double g; /* Mean anomaly of the Sun */
82 double q; /* Mean longitude of the Sun */
83 double L; /* Geocentric apparent ecliptic longitude of the Sun
84 (adjusted for aberration) */
85 // double R; /* The approximated distance of the Sun from the Earth
86 // in astronomical units (AU) */
87 double e; /* The mean obliquity of the ecliptic */
88 double RA; /* The Sun's right ascension */
89 // double D; /* The Sun's Declination */
90 double EqT; /* The Equation of Time */
91 // double SD; /* The angular semidiameter of the Sun in degrees */
92
93 // assert (jdn > 2451545);
94
95 d = (double)(jdn - 2451545); /* Remove the offset from jdn */
96 g = 357.529 + 0.98560028 * d;
97 q = 280.459 + 0.98564736 * d;
98 L = q + 1.915 * sin(convert_degrees_to_radians(g)) + \
99 0.020 * sin(convert_degrees_to_radians(2.0*g));
100 // R = 1.00014 - 0.01671 * cos(to_radians(g)) -
101 // 0.00014 * cos(to_radians(2.0*g));
102 e = 23.439 - 0.00000036 * d;
103 RA = convert_radians_to_degrees(atan2(cos(convert_degrees_to_radians(e)) * sin(convert_degrees_to_radians(L)),
104 cos(convert_degrees_to_radians(L)))/15.0);
105 *D = convert_radians_to_degrees(asin(sin(convert_degrees_to_radians(e)) * sin(convert_degrees_to_radians(L))));
106 EqT = q/15.0 - RA;
107
108 /* Resulting EqT Can be larger than 360.
109 * Therefore, it needs normalization */
110 EqT = normalize(EqT, 360.0);
111 // SD = 0.2666 / R;
112 return EqT;
113 // coord->D = D;
114 // coord->EqT = EqT;
115 // coord->R = R;
116 // coord->SD = SD;
117 }
118
119 static double
120 T(const double alpha,const double latitude,const double D)
121 {
122 double p1 = 1.0/15.0;
123 double p2 = cos(convert_degrees_to_radians(latitude)) * cos(convert_degrees_to_radians(D));
124 double p3 = sin(convert_degrees_to_radians(latitude)) * sin(convert_degrees_to_radians(D));
125 double p4 = -1.0 * sin(convert_degrees_to_radians(alpha));
126 double p5 = convert_radians_to_degrees(acos((p4 - p3) / p2));
127 double r = p1 * p5;
128 return r;
129 }
130
131 static double
132 A(const double t, const double latitude, const double D)
133 {
134 double p1 = 1.0/15.0;
135 double p2 = cos(convert_degrees_to_radians(latitude)) * cos(convert_degrees_to_radians(D));
136 double p3 = sin(convert_degrees_to_radians(latitude)) * sin(convert_degrees_to_radians(D));
137 double p4 = tan(convert_degrees_to_radians((latitude - D)));
138 double p5 = atan2(1.0, (t + p4));
139 double p6 = sin(p5);
140 double p7 = acos((p6 - p3) / p2);
141 double r = p1 * convert_radians_to_degrees(p7);
142 return r;
143 }
144
145 static double
146 get_sunrise(double dhuhr, double latitude, double altitude, double D)
147 {
148 return (dhuhr - T(0.8333 + 0.0347 * sqrt(altitude), latitude, D));
149 }
150
151 /* Prayers Function */
152 static double
153 get_fajr(double duhr, double latitude, double D, short fajr_angle)
154 {
155 double fajr = duhr - T(fajr_angle, latitude, D);
156 return fajr;
157 }
158
159 static double
160 get_duhr(double timezone, double longitude, double EqT)
161 {
162 /* Duhr equation */
163 static double duhr;
164 duhr = 12.0 + timezone - longitude/15.0 - EqT;
165 duhr = normalize(duhr, 24.0);
166 // printf("duhr = %lf\n", duhr);
167 return duhr;
168 }
169
170 static double
171 get_asr(double duhr, double latitude, double D)
172 {
173 double asr;
174 if (use_major == 1){
175 asr = duhr + A(1.0, latitude, D);
176
177 /* Hanafi */
178 } else {
179 asr = duhr + A(2.0, latitude, D);
158 180 } }
159 else if(t < array_time_pray[i]){
160 // duration to next pray
161 int seconds = difftime(array_time_pray[i], t);
162 unsigned int hours = (seconds / (60*60));
163 unsigned int minutes = (seconds / (60)) % 60;
164
165 printf("%*.*s %c %.2d:%.2d\n", 5, 5, hijri,
166 array_char_pray_name[i], hours, minutes); break;
167 };
168 };
169
170 //struct tm tm;
171 // char buf[255];
172 //
173 // strptime("2001-11-13 18:31:01", "%Y-%m-%d %H:%M:%S", &tm);
174 // strftime(buf, sizeof(buf), "%s", &tm);
175 // puts(buf);
176 // exit(EXIT_SUCCESS);
181
182 asr = normalize(asr, 24.0);
183 return asr;
184 }
185
186 static double
187 get_maghrib(double dhuhr, double latitude, double altitude, double D)
188 {
189 return (dhuhr + T(0.8333 + 0.0347 * sqrt(altitude), latitude, D));
190 }
191
192 static double
193 get_isha(double duhr, double maghrib, double latitude, double altitude,
194 double D, double isha_angle)
195 {
196 double one_min = 60.0/3600.0;
197 double isha;
198
199 /* Umm Al-Qura */
200 if (use_umm_al_qura == 1) {
201 isha = maghrib + 90 * one_min;
202
203 /* Ramadan Umm Al-Qura */
204 } else if (is_ramadan == 1){
205 isha = maghrib + 120 * one_min;
206
207 /* Use isha_angle */
208 } else {
209 isha = duhr + T(isha_angle, latitude, D);
210 }
211
212 isha = normalize(isha, 24.0);
213 return isha;
214 }
215
216 static double
217 get_next_fajr(double fajr)
218 {
219 return fajr;
220 }
221
222 void
223 tests(void)
224 {
225 time_t t = time(NULL);
226 struct tm current_date = *localtime(&t);
227 int day = current_date.tm_mday;
228 int month = current_date.tm_mon + 1;
229 int year = current_date.tm_year + 1900;
230 printf("Today Date\t%.2i %.2i %.2i\n\n", day, month, year);
177 231 } }
178 232
179 233 int int
180 234 main(void) main(void)
181 235 { {
236 /* Current date time */
182 237 time_t t = time(NULL); time_t t = time(NULL);
183 struct tm tm_variable = *localtime(&t);
184
185 // Cache file name
186 static char cache_file[32];
187 sprintf(cache_file, "/tmp/%.2d-%.2d-%d.json",
188 tm_variable.tm_mday, tm_variable.tm_mon+1,
189 tm_variable.tm_year+1900);
190
191 // Chech if cache does not exists
192 if (!file_exist (cache_file)){
193 static char api_url[128];
194 sprintf(api_url,
195 "http://api.aladhan.com/v1/timingsByCity?city=%s&country=%s&method=8",
196 city, country);
197
198 // Create the cache file
199 get_page(api_url, cache_file);
200 }
238 struct tm current_date = *localtime(&t);
239 int day = current_date.tm_mday;
240 int month = current_date.tm_mon + 1;
241 int year = current_date.tm_year + 1900;
242 double julian_date = convert_gregorian_to_julian(year, month, day);
243
244 /* Equation of Time */
245 double D;
246 double equation_of_time = get_equation_time(julian_date, &D);
247 // printf("EqTmine = %lf\n", equation_of_time);
248
249 /* Today's Prayers time */
250 double duhr = get_duhr(time_zone, longitude, equation_of_time);
251 double sunrise = get_sunrise(duhr, latitude, altitude, D);
252 double fajr = get_fajr(duhr, latitude, D, fajr_angle);
253 double maghrib = get_maghrib(duhr, latitude, altitude, D);
254 double isha = get_isha(duhr, maghrib, latitude, altitude, D, isha_angle);
255 double asr = get_asr(duhr, latitude, D);
256 // time_t next_fajr = get_next_fajr(duhr);
257
258 /* Test */
259 tests();
260
261 /* Print Next Prayer left duration */
262 printf("fajr\t\t%lf\nsunrise\t\t%lf\nduhr\t\t%lf\nasr\t\t%lf\nmaghrib\t\t%lf\nisha\t\t%lf\n",
263 fajr,
264 sunrise,
265 duhr,
266 asr,
267 maghrib,
268 isha);
269
270 printf("\nUnixTime\nfaj\t\t%ld\nsunrise\t\t%ld\nduhr\t\t%ld\nasr\t\t%ld\nmaghrib\t\t%ld\nisha\t\t%ld\n",
271 convert_today_double_to_timet(fajr),
272 convert_today_double_to_timet(sunrise),
273 convert_today_double_to_timet(duhr),
274 convert_today_double_to_timet(asr),
275 convert_today_double_to_timet(maghrib),
276 convert_today_double_to_timet(isha));
201 277
202 // Read if exists cache file and print next pray left time
203 if (file_exist (cache_file)){
204 print_next_pray(t, cache_file);
205 }
206 278 return 0; return 0;
207 279 } }
File azan.h changed (mode: 100644) (index f896689..2725031)
1 /* See LICENSE file for copyright and license details.*/
1 /*=============================================================================
2 Name : azan
3 GitHub : Afify
4 Copyright : MIT
5 Version : 0.0.2
6 Description :
7 =============================================================================*/
2 8
3 9 #ifndef AZAN_H #ifndef AZAN_H
4 10 #define AZAN_H #define AZAN_H
5 11
6 /* function declarations */
7 12
8 static int file_exist(char *filename);
9 static void get_page(const char* url, const char* file_name);
10 static void print_next_pray(time_t t, char *json_file);
13 /* typedef */
14 // typedef struct{
15 // char *event_name;
16 // int hour;
17 // int min;
18 // double doubletime;
19 // time_t unixtimestamp;
20 // double equation_oftime;
21 // } Prayer;
22
23 /* function declarations */
24 static time_t convert_today_double_to_timet(double event_time);
25 static time_t convert_today_double_to_timet(double event_time);
26 static double convert_gregorian_to_julian(int year, int month, int day);
27 static double convert_degrees_to_radians(const double x);
28 static double convert_radians_to_degrees(const double x);
29 static double normalize(const double x, const double N);
30 static double get_equation_time(const unsigned long jdn, double *D);
31 static double T(const double alpha,const double latitude,const double D);
32 static double A(const double t, const double latitude, const double D);
33 static double get_sunrise(double dhuhr, double latitude, double altitude, double D);
34 static double get_fajr(double duhr, double latitude, double D, short fajr_angle);
35 static double get_duhr(double timezone, double longitude, double EqT);
36 static double get_asr(double duhr, double latitude, double D);
37 static double get_maghrib(double dhuhr, double latitude, double altitude, double D);
38 static double get_isha(double duhr, double maghrib, double latitude, double altitude, double D, double isha_angle);
39 static double get_next_fajr(double fajr);
40 void tests(void);
11 41
42 // static Prayer todays_prayers[6] = {
43 // // prayer_name, hour, min, todays_timestamp, equation_oftime
44 // {"Fajr", 0, 0, 0, 0},
45 // {"Duhr", 0, 0, 0, 0},
46 // {"Asr", 0, 0, 0, 0},
47 // {"Maghrib", 0, 0, 0, 0},
48 // {"Isha", 0, 0, 0, 0},
49 // {"NFajr", 0, 0, 0, 0},
50 // };
12 51 #endif /* AZAN_H */ #endif /* AZAN_H */
File config.h changed (mode: 100644) (index 95cffa0..82df8a1)
3 3 #ifndef CONFIG_H #ifndef CONFIG_H
4 4 #define CONFIG_H #define CONFIG_H
5 5
6 #define MI_PI 3.14159265358979323846
7
6 8 /* variable declarations */ /* variable declarations */
9 static const double time_zone = 3;
10 static const double longitude = 39.826168;
11 static const double latitude = 21.422510;
12 static const double altitude = 0;
13
14 /* Fajr Isha */
15 static const short use_umm_al_qura = 1;
16 static const short is_ramadan = 0;
17 static const double fajr_angle = 18;
18 static const double isha_angle = 18;
19
20 /* Asr */
21 static const short use_major = 1;
22
23 static const char cache_dir[] = "~/.cache/azan";
24 // static const char cache_dir[] = "/tmp/azan";
7 25
8 static const char city[] = "Mekka";
9 static const char country[] = "Saudi%20Arabia";
26 /*
27 Muslim World League 18 17
28 Islamic Society of North America (ISNA) 15 15
29 Egyptian General Authority of Survey 19.5 17.5
30 Umm al-Qura University, Makkah 18.5 90 min after Maghrib 120 Ramadan
31 University of Islamic Sciences, Karachi 18 18
32 Institute of Geophysics, University of Tehran 17.7 14*
33 Shia Ithna Ashari, Leva Research Institute, Qum 16 14
34 */
10 35
11 36 #endif /* CONFIG_H */ #endif /* CONFIG_H */
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/afify/azan

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/afify/azan

Clone this repository using git:
git clone git://git.rocketgit.com/user/afify/azan

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main