Friday 19 July 2013

Arduino Muslim prayer time and analog clock using TV

Salam.
Utilizing the Arduino TVout library, I implemented analog clock with RTC DS1307 I2C together with muslim pray time calculation. The TV picture is as below:






Uses arduino uno board connected to reverse camera TV for display, and tinyRTC for the timekeeper.
With this code and RM40 parts, we can turn all that old TV into salat time display for masjid, surau or your own house. Below is how it look like on my 40 inch LCD tv.


How it look like in PIP window:



Below is the code for this project with embedded setting for Kuala Lumpur, Malaysia. Currently not able to change via button or serial port due to memory limitation.To change clock, date, pray time calculation parameters, they need to be changed in the code accordingly.  Please refer to the comments in the code. Will enhance it again later  for user friendliness. Pray time accuracy need to be worked on further too.

// Muslim prayer time on TV by Omar Badar, July 19, 2013
// Uses the fantastic TVout library http://code.google.com/p/arduino-tvout/
// TVout RTC is code snippet from http://giantmetalrobot.blogspot.com/2011/05/arduino-analog-clock.html
// Prayer time calculation is from http://3adly.blogspot.com/2010/07/prayer-times-calculations-pure-c-code.html

#include <TVout.h>
#include "Wire.h"
//#include <pollserial.h>
#include <fontALL.h>

TVout TV;
//pollserial pserial;
const int buttonPin = 3;
#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address
// Global Variables
long previousMillis = 0;        // will store last time time was updated
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
long interval = 200;
int tvx,tvy,tvradius,x2,y2,x3,y3;
int zero=0;
char  *Day[] = {"","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
double fajr, sunRise, zuhr, asr, maghrib, isha;


// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}

// Gets the date and time from the ds1307 and prints result
void getDateDs1307()
{
// Reset the register pointer
Wire.beginTransmission(DS1307_I2C_ADDRESS);
//Wire.write(0x00);
Wire.write(zero);
Wire.endTransmission();

Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

// A few of these need masks because certain bits are control bits
second     = bcdToDec(Wire.read() & 0x7f);
minute     = bcdToDec(Wire.read());
hour       = bcdToDec(Wire.read() & 0x3f);  // Need to change this if 12 hour am/pm
dayOfWeek  = bcdToDec(Wire.read());
dayOfMonth = bcdToDec(Wire.read());
month      = bcdToDec(Wire.read());
year       = bcdToDec(Wire.read());

}

void setDateDs1307()
{
 
   // Below changes will happen when pin 3 is pull high. Short pin 3 to ground once changes to clock is done.
   // Run out of RAM for serialport or button date, lon, lat adjust. will work on it later.
   minute=38;
   hour=22;
   dayOfWeek=5;
   dayOfMonth=18;
   month=7;
    /*
   second = (byte) ((pserial.read() - 48) * 10 + (pserial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.
   minute = (byte) ((pserial.read() - 48) *10 +  (pserial.read() - 48));
   hour  = (byte) ((pserial.read() - 48) *10 +  (pserial.read() - 48));
   dayOfWeek = (byte) (pserial.read() - 48);
   dayOfMonth = (byte) ((pserial.read() - 48) *10 +  (pserial.read() - 48));
   month = (byte) ((pserial.read() - 48) *10 +  (pserial.read() - 48));
   year= (byte) ((pserial.read() - 48) *10 +  (pserial.read() - 48)); */
  
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.write(zero);
   Wire.write(decToBcd(second));    // 0 to bit 7 starts the clock
   Wire.write(decToBcd(minute));
   Wire.write(decToBcd(hour));      // for 12 hour am/pm, need to set bit 6 (also need to change readDateDs1307)
   Wire.write(decToBcd(dayOfWeek));
   Wire.write(decToBcd(dayOfMonth));
   Wire.write(decToBcd(month));
   Wire.write(decToBcd(year));
   Wire.endTransmission();
}


void printTime()
{
int hours, minutes;
char s[12];
TV.set_cursor(0,0);
TV.print( char( hour/10 + 0x30) );
TV.print( char( hour%10 + 0x30) );
TV.print(":");
TV.print( char(minute/10 + 0x30));
TV.print( char(minute%10 + 0x30));
TV.print(":");
TV.print(char (second/10+0x30));
TV.print(char (second%10+0x30));


TV.set_cursor(8,9);
TV.print(char(dayOfMonth/10+0x30));
TV.print(char(dayOfMonth%10+0x30));
TV.print("/");
TV.print(char(month/10+0x30));
TV.print(char(month%10+0x30));
TV.set_cursor(10,18);
TV.print("20");
TV.print(char(year/10+0x30));
TV.print(char(year%10+0x30));
TV.set_cursor(10,26);
TV.print(Day[dayOfWeek]);

TV.print(40,0,"< KL Waktu Sembahyang >");
doubleToHrMin(fajr, hours, minutes);
sprintf(s,"Suboh %d:%d",hours,minutes);
TV.print(93,8,s);
doubleToHrMin(zuhr, hours, minutes);
if(hours==12)
sprintf(s,"Zohr %d:%d",hours,minutes);
else sprintf(s,"Zohr %d:%d",hours-12,minutes);
//if(hours==13)sprintf(s,"Z=%d:%d",hours-12,minutes);
TV.print(96,18,s);
doubleToHrMin(asr, hours, minutes);
sprintf(s,"Asr %d:%d",hours-12,minutes);
TV.print(100,28,s);
doubleToHrMin(maghrib, hours, minutes);
sprintf(s,"Mgb %d:%d",hours-12,minutes);
TV.print(100,38,s);
doubleToHrMin(isha, hours, minutes);
sprintf(s,"Isy %d:%d",hours-12,minutes);
TV.print(100,48,s);
//TV.print(10,70,"Kuala Lumpur");

TV.draw_circle(tvx,tvy,tvradius-5,BLACK,BLACK);

float angle = second*6 ;
angle=(angle/57.29577951) ; //Convert degrees to radians 
x3=(tvx+(sin(angle)*(tvradius-6)));
y3=(tvy-(cos(angle)*(tvradius-6)));
TV.draw_line(tvx,tvy,x3,y3,WHITE);
angle = minute * 6 ;
angle=(angle/57.29577951) ; //Convert degrees to radians 
x3=(tvx+(sin(angle)*(tvradius-11)));
y3=(tvy-(cos(angle)*(tvradius-11)));
TV.draw_line(tvx,tvy,x3,y3,WHITE);
angle = hour * 30 + int((minute / 12) * 6 )   ;
angle=(angle/57.29577951) ; //Convert degrees to radians 
x3=(tvx+(sin(angle)*(tvradius-20)));
y3=(tvy-(cos(angle)*(tvradius-20)));
TV.draw_line(tvx,tvy,x3,y3,WHITE);
}


void setup()  {
pinMode(buttonPin, INPUT);
Wire.begin();
getDateDs1307() ;
//TV.begin(_NTSC,184,72);
//the circle didn't look very round with 184,72
TV.begin(_NTSC,140,85);
TV.select_font(font4x6);
TV.clear_screen();
//TV.println("TV Clock");
tvx= TV.hres()/2;
tvy=TV.vres()/2;
tvradius=TV.vres()/3 ;
//clock face
 TV.draw_circle(tvx,tvy,tvradius,WHITE);
//hour ticks
for( int z=0; z < 360;z= z + 30 ){
  //Begin at 0° and stop at 360°
  float angle = z ;
  angle=(angle/57.29577951) ; //Convert degrees to radians
  x2=(tvx+(sin(angle)*tvradius));
  y2=(tvy-(cos(angle)*tvradius));
  x3=(tvx+(sin(angle)*(tvradius-5)));
  y3=(tvy-(cos(angle)*(tvradius-5)));

  TV.draw_line(x2,y2,x3,y3,WHITE);
}
//TV.set_hbi_hook(pserial.begin(57600));
if(digitalRead(buttonPin)==HIGH) setDateDs1307();
//calcPrayerTimes(2013,7,19,101.7,3.2,8,19.5,17.5,fajr, sunRise, zuhr, asr, maghrib, isha);
}


void loop() {
// if (pserial.available()) {
//   TV.print((char)pserial.read());
//  }

// other processing here maybe 
calcPrayerTimes(year, month, dayOfMonth, 101.7, 3.2, 8, -19.5, -19, fajr, sunRise, zuhr, asr, maghrib, isha);

unsigned long currentMillis = millis();

if(currentMillis - previousMillis > interval) {
  // save the last time you printed and updated

  previousMillis = currentMillis;
  TV.delay(1);
  printTime();
  //read RTC
  getDateDs1307() ;
}

}

/*-------------------------------------------------------------------------------------*/
// PRAYER TIME (by Mahmoud Adly Ezzat, Cairo)

//convert Degree to Radian
double degToRad(double degree)
{
    return ((3.1415926 / 180) * degree);
}

//convert Radian to Degree
double radToDeg(double radian)
{
    return (radian * (180/3.1415926));
}

//make sure a value is between 0 and 360
double moreLess360(double value)
{
    while(value > 360 || value < 0)
    {
        if(value > 360)
            value -= 360;

        else if (value <0)
            value += 360;
    }

    return value;
}

//make sure a value is between 0 and 24
double moreLess24(double value)
{
    while(value > 24 || value < 0)
    {
        if(value > 24)
            value -= 24;

        else if (value <0)
            value += 24;
    }

    return value;
}

//convert the double number to Hours and Minutes
void doubleToHrMin(double number, int &hours, int &minutes)
{
    hours = floor(moreLess24(number));
    minutes = floor(moreLess24(number - hours) * 60);
}

void calcPrayerTimes(int year, int month, int day,
                     double longitude, double latitude, int timeZone,
                     double fajrTwilight, double ishaTwilight,
                     double &fajrTime, double &sunRiseTime, double &zuhrTime,
                     double &asrTime, double &maghribTime, double &ishaTime)
{
    double D = (367 * year) - ((year + (int)((month + 9) / 12)) * 7 / 4) + (((int)(275 * month / 9)) + day - 730531.5);

    double L = 280.461 + 0.9856474 * D;
    L = moreLess360(L);

    double M = 357.528 + (0.9856003) * D;
    M = moreLess360(M);

    double Lambda = L + 1.915 * sin(degToRad(M)) + 0.02 * sin(degToRad(2 * M));
    Lambda = moreLess360(Lambda);

    double Obliquity = 23.439 - 0.0000004 * D;
    double Alpha = radToDeg(atan((cos(degToRad(Obliquity)) * tan(degToRad(Lambda)))));
    Alpha = moreLess360(Alpha);

    Alpha = Alpha - (360 * (int)(Alpha / 360));
    Alpha = Alpha + 90 * (floor(Lambda / 90) - floor(Alpha / 90));

    double ST = 100.46 + 0.985647352 * D;
    double Dec = radToDeg(asin(sin(degToRad(Obliquity)) * sin(degToRad(Lambda))));
    double Durinal_Arc = radToDeg(acos((sin(degToRad(-0.8333)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));

    double Noon = Alpha - ST;
    Noon = moreLess360(Noon);


    double UT_Noon = Noon - longitude;


    ////////////////////////////////////////////
    // Calculating Prayer Times Arcs & Times //
    //////////////////////////////////////////

    // 2) Zuhr Time [Local noon]
    zuhrTime = UT_Noon / 15 + timeZone;

    // Asr Hanafi
    //double Asr_Alt =radToDeg(atan(2+tan(degToRad(latitude - Dec))));
    double Asr_Alt =radToDeg(atan(1.7+tan(degToRad(latitude - Dec))));
    // Asr Shafii
    //double Asr_Alt = radToDeg(atan(1 + tan(degToRad(latitude - Dec))));
    double Asr_Arc = radToDeg(acos((sin(degToRad(90 - Asr_Alt)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));
    Asr_Arc = Asr_Arc / 15;
    // 3) Asr Time
    asrTime = zuhrTime + Asr_Arc;

    // 1) Shorouq Time
    sunRiseTime = zuhrTime - (Durinal_Arc / 15);

    // 4) Maghrib Time
    maghribTime = zuhrTime + (Durinal_Arc / 15);


    double Esha_Arc = radToDeg(acos((sin(degToRad(ishaTwilight)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));
    // 5) Isha Time
    ishaTime = zuhrTime + (Esha_Arc / 15);

    // 0) Fajr Time
    double Fajr_Arc = radToDeg(acos((sin(degToRad(fajrTwilight)) - sin(degToRad(Dec)) * sin(degToRad(latitude))) / (cos(degToRad(Dec)) * cos(degToRad(latitude)))));
    fajrTime = zuhrTime - (Fajr_Arc / 15);

    return;
}

//end sketch



9 comments:

  1. Hey great app, I want to contribute one more Islamic Android app. Prayer timing is yet another app from Deenwise with an easy to use interface, displaying daily prayer times (Fajr, Zuhr, Asr, Magrib, Isha) according the location. This modern freeware app Prayer timing can help Muslims perform daily prayers anywhere in the world in time.
    Download for Android: Prayer Times

    ReplyDelete
  2. No need to carry a Tasbeeh in your pocket now. Deenwise makes your smartphone and smartwatch your Digital Tasbeeh. This App will help you to recite your Tasbeeh, whenever you want or where ever you want on your Android smartphone or wearable smartwatch. No need to carry a Tasbeeh in your pocket now. Deenwise makes your smartphone and smartwatch your Digital Tasbeeh. This App will help you to recite your Tasbeeh, whenever you want or where ever you want on your Android smartphone or wearable smartwatch. Best Muslim App for Android

    ReplyDelete
  3. Assalamu alaykum brother Omar,

    Thank you for sharing. I use the code above and can work smoothly except for Asr time. I get different result with the standard Asr time prayer. Do you have any clue for that?.

    Thank you

    ReplyDelete
  4. Asslamualaikum
    Terima Kasih banyak atas referensinya. Semoga Rahmat Allah menyertaimu

    ReplyDelete
  5. Asslamualaikum
    Terima Kasih banyak atas referensinya. Semoga Rahmat Allah menyertaimu

    ReplyDelete
  6. Untuk penambahan waktu azan adakah referensinya....

    ReplyDelete
  7. Untuk penambahan waktu azan adakah referensinya....

    ReplyDelete
  8. Jazakom Allahu Khayran. Nice project. Thank you.

    ReplyDelete
  9. From Canada thank you for sharing. very interesting and useful project.

    ReplyDelete