Archivo

Archivo para la categoría ‘Delphi’

Procesos y Threads (GLibWMI)

Lunes, 14 de marzo de 2016 Sin comentarios
Share Button

threadA partir de esta consulta en el clubdelphi, sobre procesos y threads he decidido crear esta entrada; Para ello he compilado la librería GLibWMI en Delphi Seatle. La última versión que hay en la web está compilada y comprobada para Delphi XE7 y funciona sin problemas, así que era de esperar que en Seatle lo hiciera también sin cambios.

Yo mismo la estoy usando en algún proyecto antiguo en Delphi 6/7  y en algunas de las versiones más nuevas de Delphi XE.

Volviendo al tema que nos ocupa, en este caso nos interesa obtener información de los threads asociados a un determinado proceso que está corriendo en la máquina.

Para ello seguiremos los siguientes pasos:

  1. Acceder a la información del proceso
  2. Acceder a la información de los threads asociados a ese proceso.

Me voy a basar en la librería GLibWMI, aunque se puede hacer lo mismo utilizando código, sino deseamos instalar librerías de componentes adicionales.

Dentro de los componentes de GLibWMI, hay algunos que ya nos permiten acceder a clases “destacadas” o “habituales”. Entre ellos se encuentra ProcessInfo, por ejemplo, que nos da información  de los procesos ejecutandose (lo usaremos para el primer paso), pero WMI tiene muchas clases más.

Para acceder a cualquier otra clase o a datos particulares de una concreta, hay un componente llamado WMISQL, que nos permite lanzar “sentencias SQL” (algo parecido) sobre clases de WMI. Este componente es el que nos permitirá acceder a la información de los Threads (para los que no tenemos componente específico).

INFORMACIÓN DEL PROCESO

La información de los procesos funcionando en la máquina nos la da la clase Win32_Process.

Podemos utilizar el componente ProcessInfo. Basta con “soltar” el componente en un formulario y activarlo.

Este componente nos ofrece una lista de objetos TProcessProperties, la propiedad ObjectCount que nos da el número de elementos encontrados y la propiedad ObjectIndex que marca el elemento actual.

Podemos encontrar y obtener datos de un proceso con un código similar a este:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var
  str:string;
  i:integer;
  p:TProcessProperties; // para abreviar
begin
  // ini
  Memo1.Lines.Clear;
  // Activarlo
  ProcessInfo1.Active := True;
  // tenemos elementos?
  if (ProcessInfo1.ObjectsCount "MAYOR QUE" 0) then begin   //!!! Cambiar "MAYOR QUE" por el operador...
    // Buscamos un proceso concreto
    for i := 0 to (ProcessInfo1.ObjectsCount -1 ) do begin
      p := ProcessInfo1.ProcessProperties;
      // es el ibServer
      if (AnsiCompareText('ibserver.exe', p.Caption) = 0) then begin
        Memo1.Lines.Add('Nombre:        ' + p.Name);
        Memo1.Lines.Add('Caption:       ' + p.Caption);
        Memo1.Lines.Add('CommandLine:   ' + p.CommandLine);
        Memo1.Lines.Add('Path del EXE:  ' + p.ExecutablePath);
        Memo1.Lines.Add('Handle:        ' + p.Handle);
        Memo1.Lines.Add('Prioridad:     ' + IntToStr(p.Priority));
        Memo1.Lines.Add('Identificador: ' + IntToStr(p.ProcessId));
        Memo1.Lines.Add('Num. threads:  ' + IntToStr(p.ThreadCount));
 
        Break
      end;
      // Siguiente
      ProcessInfo1.ObjectIndex := ProcessInfo1.ObjectIndex + 1;
    end;
  end;
end;

 

Si lo ejecutamos obtendremos algo como esto:

En este caso, el componente ProcessInfo no es el más adecuado, ya que estamos obteniendo la información de TODOS los procesos, cuando sólo queremos acceder a uno sólo (ibserver, en el ejemplo anterior).

Para este caso, es más conveniente utilizar el componente WMISQL. Ya que podemos “minimizar” el tráfico de datos que solicitamos.

Para ello, este componente posee la propiedad SQL.

Aquí vemos las propiedades de este componente:

Añadiremos esta sentencia:

0
SELECT * FROM Win32_Process WHERE name = "ibserver.exe"

Si tan sólo queremos algunos datos, podemos afinar más la consulta para dejarla así:

0
1
SELECT Caption, CommandLine, ExecutablePath, Name, Handle, Handlecount, 
Priority, ProcessId, ThreadCount FROM Win32_Process WHERE name = "ibserver.exe"

 

Una vez activamos el componente, podemos acceder al resultado de la siguiente manera (vemos 2 opciones diferentes utilizando un TMemo -con la respuesta tal cual la da WMI- y un ValueListEditor -cuadro inferior-).

0
1
2
3
4
5
6
7
8
9
10
   // ini
  Memo1.Lines.Clear;
  // Activar
  WMISQL1.Active := True;
  // tenemos elementos?
  if (WMISQL1.ObjectsCount > 0) then begin
    // respuesta de WMI
    Memo1.Lines.Text := WMISQL1.AllProperties.Text;
    // Lista de propiedades
    ValueListEditor1.Strings.AddStrings(WMISQL1.Properties);
  end;

Como resultado obtendremos algo como esto:

Vemos que la propiedad ThreadCount nos devuelve 5.

 

INFORMACIÓN DE THREADS

Volviendo al tema original, una vez tenemos el identificador de nuestro proceso (en este caso el ProcessID=5848), necesitamos obtener los threads de este proceso y los datos asociados.

Para ver más información, podéis acceder a este link donde están todas las propiedades accesibles, la explicación de cada una de ellas y los diferentes valores que adoptan.

Vamos a utilizar en este caso otro componente WMISQL (o reaprovechar el mismo) y cambiaremos la consulta por esta otra:

0
SELECT * FROM Win32_Thread WHERE ProcessHandle=5848

 

Si activamos el componente en diseño (que se puede hacer) ya podemos ver que la propiedad ObjectCount es 5, por lo tanto ibserver tiene en este momento, 5 threads en marcha que dependen de él.

Con el siguiente código podemos obtener información de cada uno de ellos:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var
  i, j:integer;
  str:string;
  h, m, s:int64;
  p:TStrings;  // para abreviar
begin
  // ini
  Memo1.Lines.Clear;
  ValueListEditor1.Strings.Clear;
  // Activar
  WMISQL1.Active := True;
  // tenemos elementos?
  if (WMISQL1.ObjectsCount > 0) then begin
    // recorrer los threads y obtener datos
    for i := 0 to (WMISQL1.ObjectsCount - 1) do begin
      p := WMISQL1.Properties;
      j := StrToIntDef(p.Values['ElapsedTime'], 0); // milisegundos
      if (j > 0) then begin
      h := (j DIV 3600000);                        // horas
      m := (j - (h * 3600000)) DIV 60000;          // minutos
      s := (j MOD 60000) DIV 1000;                 // segundos
        Memo1.Lines.Add(Format('Tiempo ejec.:   %d:%d:%d', [h, m, s]));
      end;
      Memo1.Lines.Add('Handle:         ' + p.Values['Handle']);
      Memo1.Lines.Add('Prioridad:      ' + p.Values['Priority']);
      Memo1.Lines.Add('Prioridad base: ' + p.Values['PriorityBase']);
      Memo1.Lines.Add('Id. proceso:    ' + p.Values['ProcessHandle']);
      Memo1.Lines.Add('Estado:         ' + p.Values['ThreadState']);
      Memo1.Lines.Add('··········································');
    end;
  end;
end;

 

El resultado al mostrarlo por pantalla será algo similar a esto:

Con esto ya hemos acabado. La idea es mostrar la potencia de WMI y la sencillez con la que podemos utilizar esa información accediendo desde Delphi. Como os he dicho, podéis acceder a WMI sin necesidad de componentes, utilizando código delphi.

En entradas anteriores hemos comentado cómo hacerlo.

Un saludo y hasta la próxima.

Share Button
Categories: Delphi, Ejemplos, GLibWMI, WMI Tags: , ,

Yo ya tengo el mío…

Miércoles, 2 de marzo de 2016 Sin comentarios
Share Button

Pues eso, tal y como reza el título, yo ya tengo el mío.  :-DTapa_libro

No hace muchos días, de la mano de Danysoft (partner oficial de Embarcadero en España), se publicó el último libro de Francisco Charte; “Programación de aplicaciones Delphi con acceso a Bases de Datos”.  Pues ayer ya llegó mi copia.

No puedo opiniar todavía en profundidad, pues apenas lo he ojeado por encima, pero la verdad es que tiene una pinta fantástica.

Está centrado en la librería de acceso a datos que viene actualmente con las versiones de delphi, FireDAC y que nos da acceso multiplataforma a  las Bases de Datos más utilizadas en el mercado. Más que las explicaciones que yo pueda dar, os recomiendo que reviséis el índice completo del libro que se puede descargar en PDF desde aquí.

Personalmente me han llamado la atención algunos puntos, pero que supongo que a vosotros os pueden interesar muchos otros de los que se tratan:

  • Aplicaciones con Interbase embebido
  • Bases de Datos en memoria con FireDAC
  • Bases de Datos y Unicode
  • Servicios REST
  • Todo lo refrente a multiplataforma
  • Configuración de FireDAC

Personalmente no he trabajado casi nada con FireDAC (en lo que se refiere a proyectos “en serio”) así que aunque imagino que en su mayor parte se utilizan de forma similar a otras librerías de acceso a datos, siempre está bien tener un punto de referencia para llegar un poco más allá y profundizar un poco.

Si alguien tiene opiniones y comentarios sobre el libro y desea expresarlos, pues sois libres de participar y dar vuestra opinión aquí.

Un saludo y hasta la próxima.

IMG_20160226_174910

IMG_20160226_175022

Share Button
Categories: Bases de Datos, Danysoft, Delphi Tags: ,

Hablando del tiempo… (OpenWeatherMap) 2/2

Lunes, 21 de diciembre de 2015 1 comentario
Share Button

Para complementar la entrada anterior (Hablando del tiempo… (OpenWeatherMap) 1/2)  y “acabarla” me queda publicar el desarrollo móvil correspondiente a la aplicación que vimos anteriormente.
Como ya os comenté en la entrada anterior, el código a utilizar es prácticamente el mismo que hemos utilizado en las aplicaciones para windows (VCL). La mayor diferencia que me he encontrado en el tratamiento de la respuesta JSON que obtenemos del servidor.

Para versiones antiguas de Delphi, podéis utilizar si lo necesitáis la misma librería que ya he recomendado aquí otras veces. Se trata de lkJSON que podéis encontrar en Sourceforge.
En las nuevas versiones de Delphi ya está disponible la unit System.JSON, con lo necesario para no utilizar librerías externas.

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
function TForm1.ParseTiempoCiudadesHist(AObjResp: TlkJSONobject; var ATiempoProxHoras: TTiempoProxHoras): Boolean;
var
  i, j, num, index:integer;
  oHorasList, OWList:TlkJSONlist;
  oHora, oCoord, oMain, oWind, oWeather:TlkJSONobject;
  Str:String;
begin
  // ini
  Result := False;
  // Si no está asignado salimos..
  if not Assigned(AobjResp) then begin
    Exit;
  end;
    // Si hay error no parseamos
    if IsErrorResponse(AObjResp, errCode, ErrMsg) then begin
    Exit;
  end;
 
  // proteccion para el parseo
  try
    // cod. devuelto (datos principales
    ATiempoProxHoras.Cod := errCode;
 
    num := AObjResp.IndexOfName('count');
    if (num <> -1) then begin
      num := GetAsInteger(AObjResp.Field['count'].Value);
    end;
 
    // si no hay ciudades
    if (num = 0) then begin
      MessageDlg('No hay ninguna ciudad que coincida con ese código [nombre,pais].', mtWarning, [mbOK], 0);
      Exit;
    end;
 
    // Lista de horas (Lista)
    TlkJSONBase(oHorasList) := AObjResp.Field['list'];
    // array de elementos
    SetLength(ATiempoProxHoras.TiempoHora, oHorasList.Count);
    // Quedarse con el primier elemento de la lista...
    for i := 0 to (oHorasList.Count - 1) do begin
      // datos de la primera ciudad
      TlkJSONBase(oHora) := oHorasList.Child[i];
      // datos básicos
      ATiempoProxHoras.TiempoHora[i].dt_text := GetAsString(oHora.Field['dt_txt'].Value);
      // convertir fecha-Hora
      Str := ATiempoProxHoras.TiempoHora[i].dt_text;
      ATiempoProxHoras.TiempoHora[i].dt := EncodeDateTime(
        StrToIntdef(Copy(Str, 1, 4), 0),
        StrToIntdef(Copy(Str, 6, 2), 0),
        StrToIntdef(Copy(Str, 9, 2), 0),
        StrToIntdef(Copy(Str, 12, 2), 0),
        StrToIntdef(Copy(Str, 15, 2), 0),
        StrToIntdef(Copy(Str, 18, 2), 0), 0);
 
      // Load Main
      TlkJSONBase(oMain) := oHora.Field['main'];
      ATiempoProxHoras.TiempoHora[i].Main.temp := GetAsFloat(oMain.Field['temp'].Value);
      ATiempoProxHoras.TiempoHora[i].Main.tempmin := GetAsFloat(oMain.Field['temp_min'].Value);
      ATiempoProxHoras.TiempoHora[i].Main.tempmax := GetAsFloat(oMain.Field['temp_max'].Value);
      ATiempoProxHoras.TiempoHora[i].Main.pressure := GetAsFloat(oMain.Field['pressure'].Value);
      ATiempoProxHoras.TiempoHora[i].Main.humidity := GetAsInteger(oMain.Field['humidity'].Value);
 
      // Load weather
      TlkJSONBase(OWList) := oHora.Field['weather'];
      TlkJSONBase(oWeather) := oWList.Child[0];
      ATiempoProxHoras.TiempoHora[i].Weather.id := GetAsInteger(oWeather.Field['id'].Value);
      ATiempoProxHoras.TiempoHora[i].Weather.main := GetAsString(oWeather.Field['main'].Value);
      ATiempoProxHoras.TiempoHora[i].Weather.desc := GetAsString(oWeather.Field['description'].Value);
      ATiempoProxHoras.TiempoHora[i].Weather.icon := GetAsString(oWeather.Field['icon'].Value);
    end;
 
    Result := True;
  except
    // si hay error, FALSe
    Result := False;
  end;
end;

Posíblemente las mayores diferencias (que en realidad no son tantas) se encuentran en la parte en la que accedemos a la lista de elementos que nos devuelve el WebService.

La estructura que utilizamos para almacenar estos datos, la podéis ver en el código del proyecto (todas estas definiciones están englobadas en la unit UTWeatherClass) y es la siguiente:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// estructura para varias horas
TTiempoProxHoras = record
    Cod:Integer;			// cod. tiempo
    City:string;
    Country:string;
    TiempoHora:array of TTiempoProxHora;  // Array para cada hora
End;
// datos para una hora
TTiempoProxHora = record
    dt:TDateTime;
    dt_text:string;
    main:TMain;
    weather: TWeather;  // datos de tiempo
end;
// Main para tiempo
TMain = record
    temp:double;        // temperatura
    humidity:double;    // humedad %
    pressure:double;
    tempmin:double;
    tempmax:double;
    sealevel:Double;   // atm  presure
    grndlevel:Double;
end;
// Tiempo
TWeather = record
    id:integer;
    main: string;
    desc: string;
    icon: string;
end;

Hago un inciso.

Esta unit, es un buen ejemplo de cómo compartir código entre aplicaciones que van a ser desarrolladas para diferentes plataformas.

Delphi permite desarrollar aplicaciones multiplataforma. Eso no significa que la misma aplicación la podamos compilar y funcione en Windows, Android, iOS y OSX. En teoría si, pero en la prácira salvo alguna excepción contada, tendremos que desarrollar cosas distintas. Sin ir más lejos, es difícil que un interface para Android nos pueda ser útil para una aplicación Windows.

Eso se traduce en que al final (salvo contadas excepciones, como he dicho) tendremos que diseñar un interface “personalizado” para cada plataforma, y reaprovechar todo el código que podamos, siendo responsables en el diseño de nuestra aplicación.
No es algo nuevo de ahora, desde hace tiempo, un buen diseño aboga por la separación entre la interficie y la “lógica de negocio”; Pues esto da valor a  esa afirmación.

Volviendo al tema del tiempo, nuestra implementación utilizando la librería System.JSON, será la siguiente:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Parsea varias horas de tiempo para una ciudad
function TFormMain.ParseTiempoCiudadesHist(AObjResp: TJSONobject; var ATiempoProxHoras: TTiempoProxHoras): Boolean;
var
  i, j, num, index:integer;
  oCityList, oList, oArr:TJSONArray;
  oDatosHora, oCoord, oMain, oWind, oWeather:TJSONobject;
  Str:String;
  oPair, oCity:TJSONPair;
  oItem:TJSONValue;
begin
  // ini
  Result := False;
  // Si no está asignado salimos..
  if not Assigned(AobjResp) then begin
  	Exit;
  end;
  // Si hay error no parseamos
	if IsErrorResponse(AObjResp, errCode, ErrMsg) then begin
  	Exit;
  end;
 
  // proteccion para el parseo
  try
    // cod. devuelto (datos principales
    ATiempoProxHoras.Cod := errCode;
 
    // buscar la ciudad
    oCity := TJSONPair(AObjResp.Get('city'));
    ATiempoProxHoras.City := GetJSONPairItemString(oCity, 'name');
    ATiempoProxHoras.Country := GetJSONPairItemString(oCity, 'country');
 
    // Parsear lal lista de horas
    oArr := TJSONArray(AObjResp.Get('list').JsonValue);
    num := oArr.size;
    // Si no ha encontrado ninguna, salimos...
    if (num = 0) then begin
      MessageDlg('No hay ninguna ciudad que coincida con ese código [nombre,pais].', TMsgDlgType.mtWarning, [TMsgDlgBtn.mbOK], 0);
      Exit;
    end;
    // Tamaño de array que devolvemos
    Setlength(ATiempoProxHoras.TiempoHora, num);
    // Recorrido por las diferentes horas
    for i := 0 to (num - 1) do begin
      oDatosHora := TJSONObject(oArr.Get(i));
 
      // fecha/Hora
      ATiempoProxHoras.TiempoHora[i].dt_text := GetAsString(oDatosHora.GetValue('dt_txt').Value);
      Str := ATiempoProxHoras.TiempoHora[i].dt_text;
      // convertir fecha-Hora
      ATiempoProxHoras.TiempoHora[i].dt := EncodeDateTime(
        StrToIntdef(Copy(Str, 1, 4), 0),
        StrToIntdef(Copy(Str, 6, 2), 0),
        StrToIntdef(Copy(Str, 9, 2), 0),
        StrToIntdef(Copy(Str, 12, 2), 0),
        StrToIntdef(Copy(Str, 15, 2), 0),
        StrToIntdef(Copy(Str, 18, 2), 0), 0);
      // Parseo de Main
      oPair := TJSONPair(oDatosHora.Get('main'));
      // Los de main
      ATiempoProxHoras.TiempoHora[i].main.temp := GetJSONPairItemFloat(oPair, 'temp');
      // Los de main
      ATiempoProxHoras.TiempoHora[i].Main.temp := GetJSONPairItemFloat(oPair, 'temp');
      ATiempoProxHoras.TiempoHora[i].Main.tempmin := GetJSONPairItemFloat(oPair, 'temp_min');
      ATiempoProxHoras.TiempoHora[i].Main.tempmax := GetJSONPairItemFloat(oPair, 'temp_max');
      ATiempoProxHoras.TiempoHora[i].Main.pressure := GetJSONPairItemFloat(oPair, 'pressure');
      ATiempoProxHoras.TiempoHora[i].Main.sealevel := GetJSONPairItemFloat(oPair, 'sea_level');
      ATiempoProxHoras.TiempoHora[i].Main.grndlevel := GetJSONPairItemFloat(oPair, 'grnd_level');
      ATiempoProxHoras.TiempoHora[i].Main.humidity := GetJSONPairItemFloat(oPair, 'humidity');
      // weather
      oList := TJSONArray(oDatosHora.Get('weather').JsonValue);
      oWeather := TJSONObject(oList.Get(0));
      ATiempoProxHoras.TiempoHora[i].weather.id := StrToInt(oWeather.GetValue('id').Value);
      ATiempoProxHoras.TiempoHora[i].weather.main := oWeather.GetValue('main').Value;
      ATiempoProxHoras.TiempoHora[i].weather.desc := oWeather.GetValue('description').Value;
      ATiempoProxHoras.TiempoHora[i].weather.icon := oWeather.GetValue('icon').Value;
    end;
 
    Result := True;
  except
		// si hay error, FALSe
    Result := False;
  end;
end;

prox_horasAl igual que este, podeís comparar el resto de procedimientos que recuperan datos del WebService y los transforman y veréis que son bastante similares y fáciles de adaptar.

Otra cosa que podéis ver funcionando en el ejemplo son los Frames.

Hasta ahora no los había utilizado en desarrollo móvil y decidí realizar la prueba con este ejemplo, ya que se ajustaban perfectamente a la necesidad de la visualización de datos atmotféricos en la próximas horas.

Volvemos a la misma idea de antes. La creación del frame es diferentes en ambos proyectos (sólo de la parte visual), en este caso obligado puesto que uno está diseñado con la VCL y el otro con Firemonkey, pero a partir de ahí, la utilización dentro del proyecto y el código utilizado es casi idéntico.

El funcionamiento ha sido el esperado y en todas las plataformas se ha comportado correctamente.

Os dejo algunas imágenes de cómo se ve la aplicación funcionando en las diferentes plataformas.

droid@screen-1 droid@screen-4

 droid@screen-3 droid@screen-2

ios4  iOS3

iOS2  iOS1

Y un pequeño vídeo de la compilación y ejecución en los diferentes sistemas.

Os dejo también el código fuente del proyecto, que se añade a los de la anterior entrada (Hablando del tiempo… (OpenWeatherMap) 1/2).

<CODIGO_FUENTE_PROYECTO>

Actualización (21/12/2015): Estoy subiendo la aplicación a la tienda de Google, para que podáis probarla desde allí. En cuanto esté disponible os adjunto el enlace.

Actualización (21/12/2015 18:30): Ya está activa la aplicación y podeís descargarla desde el siguiente enlace:

https://play.google.com/store/apps/details?id=com.embarcadero.ComoEstaElTiempo

GooglePlay

Hasta la próxima.

Share Button
Categories: Android, Código, Delphi, iOS, JSON Tags: , , ,

Hablando del tiempo… (OpenWeatherMap) 1/2

Viernes, 4 de diciembre de 2015 8 comentarios
Share Button

clima_gdeHace unos días pensaba en un tema para una nueva entrada del blog.
No tenía ideas, así que como solemos hacer aquí cuando no tenemos de qué hablar, se me ocurrió “hablar del tiempo”… (gracias a Javi desde aquí, que me fue realmente el que me puso en la pista del tema ;-) ).

Pues ya está, decidido, hablemos del tiempo.

Tenía en mente escribir sobre algunas de las novedades de las últimas versiones de RAD Studio y utilizaremos el tema para realizar algunas pruebas y demostrar cómo funcionan. Para ellos y para hablar del tiempo, vamos a utilizar en la entrada OpenWeatherMap.

¿Qué es OpenWeatherMap?

Según la web se describe como, “un servicio que provee de datos del tiempo de más de 200.000 ciudades y de todas las ubicaciones geográficas que se encuentra disponible en la web OpenWeatherMap.org y también a través de API. La idea del servicio está inspirada en OpenStreetMap y Wikipedia que ofrecen la información gratuita y disponible para todo el mundo.”

 APY Key

OpenWeatherMap es un servicuio gratuito y para poder trabajar con él, deberemos crear una cuenta y así acceder a una API Key, que es obligatoria a la hora de realizar peticiones a la web.

Para esta entrada y los ejemplos de código he dado de alta una cuenta gratuíta y he obtenido la siguiente API Key:

278857e8dee51f914026df21d0d40c19

AVISO: Para seguir esta entrada y probar los ejemplos, podéis usar esta clave, pero si váis a programar aplicaciones o vuestros propios ejemplos, os aconsejo que déis de alta vuestra propia cuenta y obtengáis vuestra clave, pues en cualquier momento ésta puede dejar de estar activa.

La explicación completa de cómo utilizar el valor de la “API KEY” lo tenéis en este link.

Acceso a la API

Toda la documentación de la API de OpenWeatherMap está disponible en esta dirección.  Muy clara y muy bien documentada y con multitud de ejemplos que muestran cómo se comporta.

Todas o casi todas las opciones y consultas que podamos necesitar están disponibles y la cantidad de datos y detalles acerca del tiempo que podemos obtener es bastante grande.

Podemos consultar en tiempo en una ciudad o ubicación en este preciso momento, a partir de bastantes datos, pero también predicciones futuras a intervalos de horas o días. Es muy sencillo conocer, por ejemplo, el tiempo que nos espera en los próximos 7 días o la cantidad de precipitaciones o temperatura que hará en las próximas horas.
Los datos que se proporcionan incluyen diversidad de parámetros (a parte de los básicos), como pueden ser todos los referentes a lluvias, viento, nubes, nieve,…

Un ejemplo…

Podemos ver el funcionamiento con un ejemplo sencillo.

Una llamada como lo que os muestro a continuación:

http://api.openweathermap.org/data/2.5/find?&q=Barcelona,es&lang=es&units=metric&APPID=278857e8dee51f914026df21d0d40c19

Nos devolverá (según los parámetros indicados), el tiempo actual en Barcelona (ES), con los mensajes en castellano (lang=es) y en unidades del sistema métrico (units=metric –la alternativa es el Imprerial utilizado en Estados Unidos principalmente). Por defecto, como no hemos expresado nada, se devolverá en formato JSON, aunque también se puede pedir la respuesta en XML.

respuesta1

(acceder a la respuesta como texto)

Aquí podemos ver el resultado de esta consulta.

Las unidades en que están expresados los datos, así como el formato de cada uno de ellos, podéis consultarlo en la Referencia a la API, de la que ya hemos hablado antes.

Obtener tiempo en una ciudad

Podemos obtener el tiempo actual en una ciudad de una forma similar a la que hemos visto en el ejemplo anterior.  También hay otras opciones (interesantes para dispositivos móviles) como por ejemplo, obtener el tiempo en un lugar determinado a partir de las coordenadas GPS.

De esta forma, si obtenemos las coordenadas desde nuestro dispositivo, podemos realizar una llamada similar a esta:

http://api.openweathermap.org/data/2.5/weather?lat=41.390&lon=2.154&APPID=278857e8dee51f914026df21d0d40c19

En este caso la llamada se hace utilizando los valores GPS (lat=41.390&lon=2.154) y en la propia respuesta (en la parte final) podemos ver  la ciudad/país a la que pertenecen dichas coordenadas.


“sys”: {
“message”: 0.0027,
“country”: “ES”,
“sunrise”: 1446531928,
“sunset”: 1446569027
},
“id”: 3128760,
“name”: “Barcelona”,
“cod”: 200
}

Ahora de lo que se trata, es de plasmar esto en una aplicación.

img_jsonVamos a empezar de menos a más, así que la primera versión que vamos a ver está compilada con Delphi 7 (sí Delphi 7, no delphi XE 7). Y veremos que salvo la librería de tratamiento de JSON, mucho código -salvo vistas-) es el mismo que posteriormente vamos a compilar para Windows con una versión 10 Seatle y para móviles, tanto Android como iOS. Así, que ciertamente, si programáis con un poco de “vista”, el código que generamos en gran parte puede ser reutilizable en las nuevas plataformas.

Para tratamiento de JSON en verisones antiguas, he utilizado la librería ulkJSON (disponible en Sourceforge), de la que ya he hablado otras veces. Funciona muy bien y es una buena opción si posteriormente tenemos que actualizar, porque como veremos en otra entrada, el tratamiento de una respuesta es bastante similar utilizando esta librería, a realizarlo con la unit JSON que encontraremos en las versiones modernas de delphi (así que la migración luego será poco traumática).

Para una respesta como esta, que es la que obtenemos cuando solicitamos los datos sobre una ciudad:

respuesta_json

(obtener un fichero de texto con la respuesta)

Utilizaremos un código como este:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Parsea la respuesta de varias ciudades a una estructura que nos ha devuelto la web
function TForm1.ParseTiempoCiudades(AObjResp:TlkJSONobject; var ATiempoObj:TTiempoStruct):Boolean;
var
  i, j, num, index:integer;
  oCityList, OWList:TlkJSONlist;
  oCity, oCoord, oMain, oWind, oWeather:TlkJSONobject;
begin
  // ini
  Result := False;
  // Si no está asignado salimos..
  if not Assigned(AobjResp) then begin
    Exit;
  end;
  // Si hay error no parseamos
  if IsErrorResponse(AObjResp, errCode, ErrMsg) then begin
    Exit;
  end;
 
  // proteccion para el parseo
  try
    // cod. devuelto (datos principales
    ATiempoObj.Cod := errCode;
 
    num := AObjResp.IndexOfName('count');
    if (num &lt;&gt; -1) then begin
      num := GetAsInteger(AObjResp.Field['count'].Value);
    end;
 
    // si no hay ciudades
    if (num = 0) then begin
      MessageDlg('No hay ninguna ciudad que coincida con ese código [nombre,pais].', mtWarning, [mbOK], 0);
      Exit;
    end;
 
    // Ciudades (Lista)
    TlkJSONBase(oCityList) := AObjResp.Field['list'];
    // datos de la primera ciudad
    TlkJSONBase(oCity) := oCityList.Child[0];
    // datos básicos
    ATiempoObj.id := GetAsInteger(oCity.Field['id'].Value);
    ATiempoObj.Name := GetAsString(oCity.Field['name'].Value);
    // Parseo de coordenadas
    TlkJSONBase(oCoord)  	 	:= oCity.Field['coord'];
    ATiempoObj.Coord.Lat	 	:= GetAsFloat(oCoord.Field['lat'].Value);
    ATiempoObj.Coord.Lon	 	:= GetAsFloat(oCoord.Field['lon'].Value);
    // main
    TlkJSONBase(oMain) := oCity.Field['main'];
    ATiempoObj.Main.temp := GetAsFloat(oMain.Field['temp'].Value);
    ATiempoObj.Main.tempmin := GetAsFloat(oMain.Field['temp_min'].Value);
    ATiempoObj.Main.tempmax := GetAsFloat(oMain.Field['temp_max'].Value);
    ATiempoObj.Main.pressure := GetAsFloat(oMain.Field['pressure'].Value);
    ATiempoObj.Main.humidity := GetAsInteger(oMain.Field['humidity'].Value);
    // Viento
    TlkJSONBase(oWind) := oCity.Field['wind'];
    ATiempoObj.Wind.speed := GetAsFloat(owind.Field['speed'].Value);
    ATiempoObj.Wind.deg := GetAsInteger(oWind.Field['deg'].value);
    // Weather
    TlkJSONBase(OWList) := oCity.Field['weather'];
    // array de elementos
    SetLength(ATiempoObj.Weather, OWList.Count);
    // Recorrer la lista de objetos.
    for j := 0 to (oWList.Count - 1) do begin
      // Datos weather
      TlkJSONBase(oWeather) := oWList.Child[j];
      ATiempoObj.Weather[j].id := GetAsInteger(oWeather.Field['id'].Value);
      ATiempoObj.Weather[j].main := GetAsString(oWeather.Field['main'].Value);
      ATiempoObj.Weather[j].desc := GetAsString(oWeather.Field['description'].Value);
      ATiempoObj.Weather[j].icon := GetAsString(oWeather.Field['icon'].Value);
    end;
 
    Result := True;
  except
    // si hay error, FALSe
    Result := False;
  end;
end;

Para probar el acceso al servicio, las peticiones básicas y la librería para “parsear” la respuesta JSON, he realizado una aplicación en Delphi. Debajo podéis ver la compilación en Delphi 7  y Delphi Seatle (en el segundo caso se aplican algunos de los nuevos estilos que vienen para Windows 10). Salvo eso, el resto de código es el mismo para ambas compilaciones.

TiempoAtmosferico

Os adjunto el video de Youtube con la versión de Delphi Seatle.

Por último os dejo los links de ambos proyectos, de las librerías y de alguna cosa más relacionada.

Para la siguiente entrada dejo las aplicaciones desarrolladas para plataforma móviles y alguna cosita más.

Como siempre, cualquier comentario o sugerencia será bienvenido.

Share Button
Categories: Aplicación, Delphi, OOP, REST Tags:

Presentación de Rad Studio 10 Seatle en Barcelona

Miércoles, 25 de noviembre de 2015 3 comentarios
Share Button

Como viene siendo habitual cuando desde Embarcadero se presenta una nueva versión de Rad Studio, Danysoft realiza el “Iberian Tour” por diferentes ciudades de España para presentar las novedades del producto. Es este caso hoy día 25 se ha realizado la de Barcelona.

Podemos revisar las demos y leer algo de documentación, pero siempre es interesante asistir a una presentación en vivo. Las preguntas, las respuestas, las propias demos, el feedback y las sensaciones son diferentes a las que uno experimenta cuando está allí. Además de que como siempre he dicho, es una oportunidad para ver a diferentes amigos y excompañeros de trabajo que asisten a estas conferencias.

La presentación de hoy ha estado a cargo de Luis Navarro, Product Manager de Embarcadero.

Os adjunto algunas fotos de la presentación de hoy.

IMG_20151125_115852

IMG_20151125_115925

IMG_20151125_115908

IMG_20151125_135526b

También en este link del ClubDelphi podéis ver algunas de la presentación en Valencia (que han colgado la gente de Danysoft) y os invito a que publiquéis las de las otras ciudades si es que tenéis la oportunidad de poder asistir, así como dejar vuestras impresiones si os aperetece.

En cuanto al propio RAD Studio y en concreto a Delphi, pues qué decir. La verdad es que esta versión 10 (Seatle) tiene muy buena pinta y aunque no la he probado a fondo, sigue la misma línea ascendente de las anteriores (a mi entender). Muchas mejoras enfocadas a la estabilidad y al IDE. Y una fuerte apuesta por continuar evolucionando el desarrollo en platarformas móviles (como no podía ser de otra manera) y en seguir evolucionando la VCL para engarcharse al carro de Windows 10 (y por lo que hemos visto parece que lo ha conseguido).

Os dejo el video con las novedades de esta versión por si queréis echarle un vistazo y el link a la lista de novedades (disponible en la docwiki) de esta versión.

Un saludo y hasta la próxima.

Share Button

Replay de las sesiones de la DelphiWeek 2015

Martes, 7 de abril de 2015 Sin comentarios
Share Button

Si te perdiste las sesiones de la DelphiWeek 2015, ya están disponibles todas las sesiones en esta lista de reproducción de Embarcadero Technologies.

Vale la pena revisarlas, porque algunas son muy interesantes. Hay un poco de todo, de carácter general, técnicas, algunas más “offtopic” y otras referentes a partners y componentes comerciales.

Delphi banner

 

Aquí tenéis una lista completa de las sesiones:

Espero que las encontréis interesantes.

 

Un saludo y hasta la próxima.

Share Button

20 cumpleaños de Delphi!! #DelphiWeek 2015

Viernes, 30 de enero de 2015 1 comentario
Share Button

El próximo mes de Febrero se celebra el 20 aniversario de Delphi, concretamente el 14 de Febrero (no haré comentarios cursis sobre temas “románticos”, dado el día  ;-D  ).

Se celebra además a lo grande!

Desde el 9 al 13 de Febrero se celebrará la “#DelphiWeek”. Sesiones online donde se realizarán diferentes eventos; Según la agenda podremos disfrutar de:

  • Entrevistas
  • “Code Battles”. Batallas de código
  • Delphi Games
  • Funside of Delphi
  • Virtual Office Tours
  • Day in the Life survey
  • Global celebration of all things Delphi

Supongo que durante los próximos días iremos conociendo más detalles de los diferentes eventos.

Delphi banner

El anuncio lo ha hecho Jim McKeeth en la “community” de Embarcadero, y ya está disponible el registro para las sesiones (mañana y tarde).

Share Button

Blaise Pascal Magazine en Castellano

Viernes, 2 de enero de 2015 Sin comentarios
Share Button

Antes de nada, Feliz Año Nuevo a los que visitáis este Blog. Espero que este año 2015 sea mucho mejor que el anterior.

Quiero empezar este año nuevo con una buena noticia (o al menos a mi me lo parece) y es la que reza en el título de la entrada.

MagazinaNo se si muchos de vosotros conocéis Blaize Pascal Magazine. Se trata de una revista que se publica bajo suscripción ya hace unos años y que trata todos los temas y entornos relacionados con Object Pascal.  Delphi, Lazarus, Oxygene, FreePascal,…

Desde hace un tiempo se está haciendo un esfuerzo (y me consta por la persona que lo lleva) por parte de la revista para poder publicarla de forma asidua es castellano. Prueba de ellos son los primeros números (1, 2 y 3) que corresponden a las publicaciones en inglés (30, 31 y 32) que ya han visto la luz en nuestro idioma. En este sentido os recomiendo leer la Editorial de los números 2 y 3 donde están las líneas maestra de lo que pretenden los editores de la revista.

Todas ellas se han publicado completas en castellano de forma gratuita.

Para descargarlas podéis ir a la sección en castellano de la página.

Creo que es una buena noticia para la comunidad hispana de Delphi. No son muchas las publicaciones y libros de los que disponemos en nuestro idioma y el hecho de que se amplíe ese abanico siempre es bueno.

Veremos si la gente se anima y el proyecto sigue adelante.

Un saludo y hasta la próxima.

Share Button

Grupo Delphi Solidario facebook (888)

Martes, 18 de noviembre de 2014 2 comentarios
Share Button

descarga (1)Desde aquí mi enhorabuena al grupo de facebook, Delphi Solidario.

Originalmente empezó como un proyecto personal de Salvador Jover (Delphi Basico), pero ha transcendido de una iniciativa puntual a ser un referente para muchos usuarios. En concreto para 888 que actualmente son los miembros con los que cuenta.

Creo que esa cifra merece este referencia.  ;-)

descarga

Un saludo.

NOTA: Acabo de dejar la entrada anticuada, pues al finalizarla acabo de dar de alta al usuario 889.

Share Button
Categories: Delphi, Offtopic Tags: , , ,

Mando a distancia; Tethering con Delphi XE7

Viernes, 17 de octubre de 2014 28 comentarios
Share Button

El tema de Tethering, del que ya he hablado antes en el blog (Tethering, operaciones básicas), se incorporó a la versión XE6 de RAD Studio. Hasta ese momento podíamos utilizar esta característica para conectar aplicaciones y dispositivos utilizando Wifi.

blueT_WifiPara esta nueva versión XE7 se a añadido la posibilidad de conexión mediante Bluetooth.
Además, a las características ya existentes de conexión wifi, se han añadido opciones para poder filtrar o discriminar los dispositivos a los que nos vamos a conectar a partir de máscaras para la IP o para la subred.

Como ya he comentado anteriormente, el Tethering es una característica que podemos utilizar (aunque se haya introducido en las últimas versiones de Delphi) no sólo en aplicaciones FireMonkey (tanto móviles como de escritorio) sino también, en aplicaciones ”antiguas” diseñadas con la VCL.

INTRODUCCIÓN

La idea de esta entrada es repasar más ampliamente en las características de Tethering, de las que ya hablé anteriormente, y profundizar en las posibilidades de esta tecnología, utilizando un proyecto más complejo y completo que el que vimos en la introducción.

Para ello utilizaremos 2 aplicaciones diferentes. Una basada en la VCL y otra desarrollada con Firemonkey para dispositivos móviles.

Reproductor y Mando

Leer más…

Share Button
Categories: Delphi, Tethering, XE7 Tags: , ,