Recent

Author Topic: locale from gps  (Read 8824 times)

BLL

  • Sr. Member
  • ****
  • Posts: 266
locale from gps
« on: November 04, 2015, 12:05:11 pm »
Hi, I have a lazarus app which can get time and date from a gps attached to my RasPi. It gets the NMEA GPRMC sentence and parses it. I am NOT using gpsd at all.

What I want to do is to set the RasPi's locale to London or Madrid, according to the rough latitude value (to set British or European time), rather than having to manually change it in raspi-config.
Can I do this in code from lazarus?

Second, I want to set the RasPi time/date from the gps values from GPRMC. I have looked at the various time/date routines but can't see how to best to it.

Can anyone help please?

Thanks
Brian
RasPi, fpc 3.1.1, lazarus 1.5

Windsurfer

  • Sr. Member
  • ****
  • Posts: 362
    • Windsurfer
Re: locale from gps
« Reply #1 on: November 04, 2015, 01:59:50 pm »
Look at the help for DateTimetoSystemTime function. It shows the example below. Depending
on your need you might write to labels rather than use writeln.

Code: Pascal  [Select]
  1. Program
  2.  Example5;
  3. { This program demonstrates the DateTimeToSystemTime function }
  4. Uses
  5.  sysutils;
  6. Var
  7.  ST : TSystemTime;
  8. Begin
  9.   DateTimeToSystemTime(Now,ST);
  10. With
  11.  St do
  12. begin
  13.     Writeln ('Today is    ',year,'/',month,'/',Day);
  14.     Writeln ('The time is ',Hour,':',minute,':',Second,'.',MilliSecond);
  15. end;
  16. End
  17. .

Edit:

Look at GetEnvironmentString and GetEnvironmentCount to get you started on the environment stuff. I will add more later.
« Last Edit: November 04, 2015, 02:14:03 pm by Windsurfer »

Windsurfer

  • Sr. Member
  • ****
  • Posts: 362
    • Windsurfer
Re: locale from gps
« Reply #2 on: November 04, 2015, 05:53:56 pm »

BLL

  • Sr. Member
  • ****
  • Posts: 266
Re: locale from gps
« Reply #3 on: November 04, 2015, 08:58:38 pm »
Hi

Thanks for the info. The link doesn't seem useful as it seems to show the installed locales, rather than how to change the city, which is what I need to do.

Thanks again

Brian

Windsurfer

  • Sr. Member
  • ****
  • Posts: 362
    • Windsurfer
Re: locale from gps
« Reply #4 on: November 04, 2015, 11:00:18 pm »
It seems you are right. I found this forum link: http://forum.lazarus.freepascal.org/index.php/topic,15249.msg81651.html#msg81651

I was going to suggest using ExecuteProcess to run a unix script, but then I found this: http://free-pascal-general.1045716.n5.nabble.com/Setting-environment-variables-on-Unix-Linux-td5000973.html which suggests on the last line that the environment for a process must be set at startup.

wp

  • Hero Member
  • *****
  • Posts: 6362
Re: locale from gps
« Reply #5 on: November 04, 2015, 11:22:46 pm »
Quote
What I want to do is to set the RasPi's locale to London or Madrid, according to the rough latitude value (to set British or European time), rather than having to manually change it in raspi-config.
Can I do this in code from lazarus?
Since the borders of time zones are very irregular I do not think that there is an algorithm in any common operating system for your purpose. But if you have internet access from your raspi you could query openstreetmap as described in
http://wiki.openstreetmap.org/wiki/Nominatim#Reverse_Geocoding. The site contains a (clickable) example of how to create the query string. You can use synapse httpsend, or fpc's fpchttpclient to send the query string to the server and receive the resulting xml stream.

[EDIT]
I played a bit and ended up with this working code for two edit controls with latitude and longitude (internet access by using Synapse, i.e. package laz_synapse required):
Code: Pascal  [Select]
  1. uses
  2.   httpsend, laz2_DOM, laz2_xmlread;
  3.  
  4. function GetCountryCodeFromGPS(ALatitude, ALongitude: Double): String;
  5. const
  6.   URL_MASK = 'http://nominatim.openstreetmap.org/reverse?format=xml&lat=%g&lon=%g&zoom=18&addressdetails=1';
  7. var
  8.   stream: TStream;
  9.   doc: TXMLDocument;
  10.   node: TDOMNode;
  11.   url: String;
  12.   fs: TFormatSettings;
  13. begin
  14.   Result := '';
  15.   stream := TMemoryStream.Create;
  16.   try
  17.     fs := FormatSettings;
  18.     fs.DecimalSeparator := '.';
  19.     url := Format(URL_MASK, [ALatitude, ALongitude], fs);
  20.     if HttpGetBinary(url, stream) then
  21.     begin
  22.       stream.Position := 0;
  23.       ReadXMLFile(Doc, stream);
  24.       node := Doc.DocumentElement.FindNode('addressparts');
  25.       if node <> nil then node := node.FindNode('country_code');
  26.       if node <> nil then Result := node.TextContent;
  27.     end;
  28.   finally
  29.     stream.Free;
  30.   end;
  31. end;
  32.  
  33.  
  34. { TForm1 }
  35.  
  36. procedure TForm1.Button1Click(Sender: TObject);
  37. var
  38.   country_code: String;
  39. begin
  40.   country_code := GetCountryCodeFromGPS(
  41.     StrToFloat(EdLatitude.Text),
  42.     StrToFloat(EdLongitude.Text)
  43.   );
  44.  
  45.   if country_code <> '' then
  46.     ShowMessage(Format('Country code at latitude=%s and longitude=%s is: %s',
  47.       [EdLatitude.Text, EdLongitude.Text, country_code]))
  48.   else
  49.     ShowMessage('An error has occured querying the country code from OpenStreetMap');
  50. end;
  51.  
« Last Edit: November 05, 2015, 11:40:52 am by wp »
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

BLL

  • Sr. Member
  • ****
  • Posts: 266
Re: locale from gps
« Reply #6 on: November 05, 2015, 02:34:54 pm »
Hi, Thanks for your reply and code and I will certainly try it. However, as I only want to know whether I am in Great Britain or in mainland Europe, I can do that just by seeing if the latitude is less than the bottom of the UK.
My other problem is fpc date time utilities. I have spent ages on the documentation and am now more confused than ever!
The NMEA $GPRMC sentence gives me time in the format 120512 and date in the format 051115
This time is in UTC. As I am currently in Spain, we are  UTC+1.
I have tried to use the following code, but it still sets the RasPi to UTC. GPSList is a StringList which has been filled by DeLimitedText from the gps data string.
//set RasPi's time and date from $GPRMC
 timeString := GPSList.Strings[1]; //time of fix
//add separators to go from 123412 to 12:34:12
 Insert(':', timeString, 3);
 Insert(':', timeString, 6);
 dateString := GPSList.Strings[9]; //date of fix
//add separators to go from 051115 to 05/11/15
 Insert('/', dateString, 3);
 Insert('/', dateString, 6);
//add century
 Insert('20', dateString, 7);
//assemble time/date string to suit StrToDateTime
//t is of type TDateTime, ST of type TSystemTime
 t := StrToDateTime(dateString + ' ' + timeString);
//convert t; not sure whether this takes account of RasPi's locale as 1 hr ahead
 DateTimeToSystemTime(t, ST);
//set RasPi's clock
 SetDate(ST.day,ST.month,ST.year);
 SetTime(ST.hour,ST.minute,ST.second, 0);
//hour is still in UTC, so no good!!!
 Label5.Caption := IntToStr(ST.Hour);

What am I doing wrong?

Brian

(No hair left)
« Last Edit: November 05, 2015, 02:39:26 pm by BLL »

BLL

  • Sr. Member
  • ****
  • Posts: 266
Re: locale from gps
« Reply #7 on: November 05, 2015, 10:10:48 pm »
Hi all
The plot thickens! I decided to take myT DateTime value, produced from the gps date and time. I first checked it by converting it back to a string and all was well.
I then used DateTimeToUnix to give me the number of seconds elapsed since the date in 1970.
I then used UnixToDateTime to get back to a TDateTime, converted this to a string and lo and behold, it had lost about 29 hours!!!
I then tried adding that number of seconds to the int64 epoch value. This got it near but the difference varies each time you run the program!!
It thus appears that DateTimeToUnix and its reverse are worse than useless!
Here is the code:
//set RasPi's time and date from $GPRMC
 dateString := GPSList.Strings[9];
 timeString := GPSList.Strings[1];
 t := EncodeDateTime(StrToInt(MidStr(dateString, 5,6)),StrToInt(MidStr(dateString,3,2)),StrToInt(MidStr(dateString,1,2)),StrToInt(LeftStr(timeString,2)),StrToInt(MidStr(timeString,3,2)),StrToInt(MidStr(timeString,5,2)),0);
//t checks as correct
//ee is an int64
 ee := DateTimeToUnix(t);
//correction
 ee := ee + 63114015200;
 ST := UnixToDateTime(ee);
 DateTimeToString(G, 'hh:mm:ss DD/MM/YY', ST);
 j := FormatDateTime('hh:mm:ss', Now);
//variable difference between G and j!
 Label5.Caption := G + ', ' + j;
This is getting silly!
Brian

wp

  • Hero Member
  • *****
  • Posts: 6362
Re: locale from gps
« Reply #8 on: November 05, 2015, 10:31:32 pm »
I still don't understand. Do you want to extract the time from the string '120512' and the date from '051115'? Why don't you use the "ScanDateTime" function of unit DateUtils?
Code: Pascal  [Select]
  1. function GPSToTime(ATimeStr: String): TTime;
  2. begin
  3.   Result := ScanDateTime('hhnnss', ATimeStr);
  4. end;
  5.  
  6. function GPSToDate(ADateStr: String): TDate;
  7. begin
  8.   Result := ScanDateTime('ddmmyy', ADateStr);
  9. end;
  10.  
The time you get from the gps is UTC, isn't it? Then you should call "UniversalTimeToLocal" from the same unit to get the local time. Of course you need to provide the appropriate time-offset to this function. (Or just add/subtract the hours needed - 1 hour in TTime units is just 1/24)
« Last Edit: November 05, 2015, 10:39:57 pm by wp »
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

BLL

  • Sr. Member
  • ****
  • Posts: 266
Re: locale from gps
« Reply #9 on: November 06, 2015, 09:51:59 am »
Hi, Thanks for the reply.
I wasn't aware of that function. It does not however solve my problem of taking time and date from the gps, which is in UTC, and using it to set my RasPi's clock, which is set to UTC+1, as I am in Spain. I had presumed that if I converted the time/date from the gps to seconds after epoch, added 1 hour (3600s) and then converted back to a DateTime, I would now have the time as UTC+1, but this is not the case. It is more than 24 hours out!!!

Brian

wp

  • Hero Member
  • *****
  • Posts: 6362
Re: locale from gps
« Reply #10 on: November 06, 2015, 10:48:05 am »
Why do you work with seconds? TDateTime, TDate and TTime are counted in days: the integer part is the number of days past some reference date, the fractional part corresponds to the time after midnight, i.e. 0.25 = one quarter of a day = 24/4 = 8 o'clock.

Therefore, you have to add 1/24 to the UTC time to get to the local time in spain. Or use the "UniversalTimeToLocal" and provide a time-offset of 60 (from the source coude it can be concluded that this is in minutes).

Code: Pascal  [Select]
  1. function UTCToSpainTime(ATime: TTime): TTime;
  2. begin
  3.   Result := ATime + 1/24;
  4.   if Result > 1.0 then Result := Result - 1.0;  // if local time > 24 hrs
  5.  
  6.   // or: Result := UniversalTimeToLocal(ATime, 60);
  7. end;
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

BLL

  • Sr. Member
  • ****
  • Posts: 266
Re: locale from gps
« Reply #11 on: November 06, 2015, 04:10:44 pm »
Hi, I tried similar to that but it wouldn't work for me. I will try again! Will this work when DST applies?
Thanks very much.

Brian

wp

  • Hero Member
  • *****
  • Posts: 6362
Re: locale from gps
« Reply #12 on: November 06, 2015, 05:37:50 pm »
I suppose that DST is "daylight saving time"? There's nothing automatic in this correction. It is assumes that you know the time zone of the location where you are, and you know whether there's DST on this day or not. So, during DST, you have to add two hours (i.e. 2/24) to the UTC for Madrid.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

BLL

  • Sr. Member
  • ****
  • Posts: 266
Re: locale from gps
« Reply #13 on: November 06, 2015, 06:26:19 pm »
Thanks, that's what I thought. I already have an algorithm in C which sets/unsets the GMT/BST flag, which I can convert.

wp

  • Hero Member
  • *****
  • Posts: 6362
Re: locale from gps
« Reply #14 on: November 06, 2015, 06:36:42 pm »
I tried similar to that but it wouldn't work for me.
Did you use the symbol "n" for the minutes in the time format string? This is a bit counter-intuitive because normally I'd use "m" - but fpc wants this for "month"
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10