Delphi XE3 includes support for sensors in OSX and Windows, the classes and types necessaries to access such devices are defined as abstract classes in the System.Sensors unit and implemented in the System.Mac.Sensors unit for OSX and System.Win.Sensors unit for Windows. This article will focus in the Windows side implementation.
Windows 7 introduces the Sensor and Location API, which unifies the access to hardware devices like GPS, Light Sensors, Biometric Sensors and so on. Avoiding the need of use a specific dlls or SDK to control the sensor devices. this API is condensed on these files which are part of the Windows 7 Software Development Kit (SDK).
File name | Description |
---|---|
Sensorsapi.h | The main header file for the Sensor API. This header file contains the interface definitions. |
Sensors.h | The header file that contains definitions of platform-defined constants. |
Initguid.h | The header file that contains definitions for controlling GUID initialization.{ |
FunctionDiscoveryKeys.h | The header file that defines device ID property keys that are required when you connect to logical sensors. |
Sensorsapi.lib | A static library that contains GUID definitions for the Sensor API. |
PortableDeviceGuids.lib | A static library that contains GUID definitions for Windows Portable Devices objects. |
All these headers was translated by Embarcadero and included as part of the RTL of the Delphi XE3, these are the units which contains such translations Winapi.Portabledevicetypes, Winapi.Sensors, Winapi.Sensorsapi, Winapi.Locationapi. Fortunately an additional set of classes was added to wrap the sensors API, these classes are defined and implemented in the System.Sensors and System.Win.Sensors units. So you don’t need access directly interfaces like ISensor or ISensorManager to gain access to the sensors.
Enumerating Sensors
In order to gain access to the sensors you must get an instance to the TSensorManager class and then call the Activate method, from here you can iterate over the Sensors property or use the GetSensorsByCategory method to get an array of TSensor objects filtered by an TSensorCategory.
var LManager : TSensorManager; LSensors : TSensorArray; LSensor : TCustomSensor; begin LManager := TSensorManager.Current; LManager.Activate; try LSensors := LManager.GetSensorsByCategory(TSensorCategory.Location); for LSensor in LSensors do begin //do something end; finally LManager.Deactivate; end; end;
All the sensors share a common set of properties like the Manufacturer, Model, Serial number and so on. So extending the above code you can access such properties on this way :
var LManager : TSensorManager; LSensors : TSensorArray; LSensor : TCustomSensor; begin LManager := TSensorManager.Current; LManager.Activate; try LSensors := LManager.GetSensorsByCategory(TSensorCategory.Location); for LSensor in LSensors do begin Writeln(Format('Description : %s', [LSensor.Description])); Writeln(Format('Manufacturer : %s', [LSensor.Manufacturer])); Writeln(Format('Model : %s', [LSensor.Model])); Writeln(Format('Serial No : %s', [LSensor.SerialNo])); Writeln(Format('State : %s', [GetEnumName(TypeInfo(TSensorState),integer(LSensor.State))])); Writeln(Format('TimeStamp : %s', [DatetoStr(LSensor.TimeStamp)])); Writeln(Format('Unique ID : %s', [LSensor.UniqueID])); end; finally LManager.Deactivate; end; end;
Now depending of the sensor category, you must cast the TCustomSensor to the proper specific class, in this case we will use the TCustomLocationSensor class.
var LManager : TSensorManager; LSensors : TSensorArray; LSensor : TCustomSensor; LLocationSensor : TCustomLocationSensor; begin LManager := TSensorManager.Current; LManager.Activate; try LSensors := LManager.GetSensorsByCategory(TSensorCategory.Location); for LSensor in LSensors do begin Writeln(Format('Description : %s', [LSensor.Description])); Writeln(Format('Manufacturer : %s', [LSensor.Manufacturer])); Writeln(Format('Model : %s', [LSensor.Model])); Writeln(Format('Serial No : %s', [LSensor.SerialNo])); Writeln(Format('State : %s', [GetEnumName(TypeInfo(TSensorState),integer(LSensor.State))])); Writeln(Format('TimeStamp : %s', [DatetoStr(LSensor.TimeStamp)])); Writeln(Format('Unique ID : %s', [LSensor.UniqueID])); LLocationSensor:=LSensor as TCustomLocationSensor; LLocationSensor.Start; try Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TLocationSensorType),integer(LLocationSensor.SensorType))])); Writeln(Format('Authorized : %s', [GetEnumName(TypeInfo(TAuthorizationType),integer(LLocationSensor.Authorized))])); Writeln(Format('Accuracy : %n', [LLocationSensor.Accuracy])); Writeln(Format('Distance : %n', [LLocationSensor.Distance])); Writeln(Format('Power Consumption : %s', [GetEnumName(TypeInfo(TPowerConsumption),integer(LLocationSensor.PowerConsumption))])); Writeln(Format('Location Change : %s', [GetEnumName(TypeInfo(TLocationChangeType),integer(LLocationSensor.LocationChange))])); if TCustomLocationSensor.TProperty.Latitude in LLocationSensor.AvailableProperties then Writeln(Format('Latitude : %n', [LLocationSensor.Latitude])); if TCustomLocationSensor.TProperty.Longitude in LLocationSensor.AvailableProperties then Writeln(Format('Longitude : %n', [LLocationSensor.Longitude])); if TCustomLocationSensor.TProperty.ErrorRadius in LLocationSensor.AvailableProperties then Writeln(Format('Error Radius : %n', [LLocationSensor.ErrorRadius])); if TCustomLocationSensor.TProperty.Altitude in LLocationSensor.AvailableProperties then Writeln(Format('Altitude : %n', [LLocationSensor.Altitude])); if TCustomLocationSensor.TProperty.Speed in LLocationSensor.AvailableProperties then Writeln(Format('Speed : %n', [LLocationSensor.Speed])); if TCustomLocationSensor.TProperty.TrueHeading in LLocationSensor.AvailableProperties then Writeln(Format('True Heading : %n', [LLocationSensor.TrueHeading])); if TCustomLocationSensor.TProperty.MagneticHeading in LLocationSensor.AvailableProperties then Writeln(Format('Magnetic Heading : %n', [LLocationSensor.MagneticHeading])); if TCustomLocationSensor.TProperty.Address1 in LLocationSensor.AvailableProperties then Writeln(Format('Address1 : %s', [LLocationSensor.Address1])); if TCustomLocationSensor.TProperty.Address2 in LLocationSensor.AvailableProperties then Writeln(Format('Address2 : %s', [LLocationSensor.Address2])); if TCustomLocationSensor.TProperty.City in LLocationSensor.AvailableProperties then Writeln(Format('City : %s', [LLocationSensor.City])); if TCustomLocationSensor.TProperty.StateProvince in LLocationSensor.AvailableProperties then Writeln(Format('State/Province : %s', [LLocationSensor.StateProvince])); if TCustomLocationSensor.TProperty.PostalCode in LLocationSensor.AvailableProperties then Writeln(Format('Postal Code : %s', [LLocationSensor.PostalCode])); if TCustomLocationSensor.TProperty.CountryRegion in LLocationSensor.AvailableProperties then Writeln(Format('Country Region : %s', [LLocationSensor.CountryRegion])); finally LLocationSensor.Stop; end; Writeln; end; finally LManager.Deactivate; end; end;
Not all the properties exposed by the Windows sensors and Location API are mapped directly in the TCustomSensors class, so to access this additional data you can use the HasCustomData and CustomData indexed properties and use one of the values defined in the Winapi.Sensors unit which is the translation of the Sensors.h header file.
if LLocationSensor.HasCustomData[SENSOR_DATA_TYPE_SATELLITES_USED_COUNT] then Writeln(Format('Satellites used : %d', [ Integer(LLocationSensor.CustomData[SENSOR_DATA_TYPE_SATELLITES_USED_COUNT])]));
Sample Application
Check this sample console application which enumerates all the sensors and properties.
{$APPTYPE CONSOLE} uses System.TypInfo, System.Sensors, System.SysUtils; procedure EnumerateSensors; var LManager : TSensorManager; LCustomLocationSensor : TCustomLocationSensor; LCustomLightSensor : TCustomLightSensor; LCustomEnvironmentalSensor : TCustomEnvironmentalSensor; LCustomMotionSensor : TCustomMotionSensor; LCustomOrientationSensor : TCustomOrientationSensor; LCustomMechanicalSensor : TCustomMechanicalSensor; LCustomElectricalSensor : TCustomElectricalSensor; LCustomBiometricSensor : TCustomBiometricSensor; LCustomScannerSensor : TCustomScannerSensor; LSensor : TCustomSensor; i : Integer; begin LManager := TSensorManager.Current; LManager.Activate; //LSensors := LManager.GetSensorsByCategory(TSensorCategory.Location); if LManager.Count > 0 then for i := 0 to LManager.Count-1 do begin Writeln(Format('Sensor %d',[i+1])); Writeln('--------'); LSensor:= LManager.Sensors[i]; Writeln(Format('Category : %s', [GetEnumName(TypeInfo(TSensorCategory),integer(LSensor.Category))])); Writeln(Format('Description : %s', [LSensor.Description])); Writeln(Format('Manufacturer : %s', [LSensor.Manufacturer])); Writeln(Format('Model : %s', [LSensor.Model])); Writeln(Format('Serial No : %s', [LSensor.SerialNo])); Writeln(Format('State : %s', [GetEnumName(TypeInfo(TSensorState),integer(LSensor.State))])); Writeln(Format('TimeStamp : %s', [DatetoStr(LSensor.TimeStamp)])); Writeln(Format('Unique ID : %s', [LSensor.UniqueID])); case LSensor.Category of TSensorCategory.Location : begin LCustomLocationSensor:=LSensor as TCustomLocationSensor; LCustomLocationSensor.Start; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TLocationSensorType),integer(LCustomLocationSensor.SensorType))])); Writeln(Format('Authorized : %s', [GetEnumName(TypeInfo(TAuthorizationType),integer(LCustomLocationSensor.Authorized))])); Writeln(Format('Accuracy : %n', [LCustomLocationSensor.Accuracy])); Writeln(Format('Distance : %n', [LCustomLocationSensor.Distance])); Writeln(Format('Power Consumption : %s', [GetEnumName(TypeInfo(TPowerConsumption),integer(LCustomLocationSensor.PowerConsumption))])); Writeln(Format('Location Change : %s', [GetEnumName(TypeInfo(TLocationChangeType),integer(LCustomLocationSensor.LocationChange))])); Writeln(Format('Latitude : %n', [LCustomLocationSensor.Latitude])); Writeln(Format('Longitude : %n', [LCustomLocationSensor.Longitude])); Writeln(Format('Longitude : %n', [LCustomLocationSensor.Longitude])); Writeln(Format('Error Radius : %n', [LCustomLocationSensor.ErrorRadius])); Writeln(Format('Altitude : %n', [LCustomLocationSensor.Altitude])); Writeln(Format('Speed : %n', [LCustomLocationSensor.Speed])); Writeln(Format('True Heading : %n', [LCustomLocationSensor.TrueHeading])); Writeln(Format('Magnetic Heading : %n', [LCustomLocationSensor.MagneticHeading])); Writeln(Format('Address1 : %s', [LCustomLocationSensor.Address1])); Writeln(Format('Address2 : %s', [LCustomLocationSensor.Address2])); Writeln(Format('City : %s', [LCustomLocationSensor.City])); Writeln(Format('State/Province : %s', [LCustomLocationSensor.StateProvince])); Writeln(Format('Postal Code : %s', [LCustomLocationSensor.PostalCode])); Writeln(Format('Country Region : %s', [LCustomLocationSensor.CountryRegion])); LCustomLocationSensor.Stop; end; TSensorCategory.Light : begin LCustomLightSensor:=LSensor as TCustomLightSensor; Writeln(Format('Lux : %n', [LCustomLightSensor.Lux])); Writeln(Format('Temperature : %n', [LCustomLightSensor.Temperature])); Writeln(Format('Chromacity : %n', [LCustomLightSensor.Chromacity])); Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TLightSensorType),integer(LCustomLightSensor.SensorType))])); end; TSensorCategory.Environmental : begin LCustomEnvironmentalSensor:= LSensor as TCustomEnvironmentalSensor; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TEnvironmentalSensorType),integer(LCustomEnvironmentalSensor.SensorType))])); Writeln(Format('Temperature : %n', [LCustomEnvironmentalSensor.Temperature])); Writeln(Format('Pressure : %n', [LCustomEnvironmentalSensor.Pressure])); Writeln(Format('Humidity : %n', [LCustomEnvironmentalSensor.Humidity])); Writeln(Format('Wind Direction : %n', [LCustomEnvironmentalSensor.WindDirection])); Writeln(Format('Wind Speed : %n', [LCustomEnvironmentalSensor.WindSpeed])); end; TSensorCategory.Motion : begin LCustomMotionSensor:= LSensor as TCustomMotionSensor; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TMotionSensorType),integer(LCustomMotionSensor.SensorType))])); Writeln(Format('Acceleration X : %n', [LCustomMotionSensor.AccelerationX])); Writeln(Format('Acceleration Y : %n', [LCustomMotionSensor.AccelerationY])); Writeln(Format('Acceleration Z : %n', [LCustomMotionSensor.AccelerationZ])); Writeln(Format('Angle Accel. X : %n', [LCustomMotionSensor.AngleAccelX])); Writeln(Format('Angle Accel. Y : %n', [LCustomMotionSensor.AngleAccelY])); Writeln(Format('Angle Accel. Z : %n', [LCustomMotionSensor.AngleAccelZ])); Writeln(Format('Motion : %n', [LCustomMotionSensor.Motion])); Writeln(Format('Speed : %n', [LCustomMotionSensor.Speed])); Writeln(Format('Update Interval: %n', [LCustomMotionSensor.UpdateInterval])); end; TSensorCategory.Orientation : begin LCustomOrientationSensor:= LSensor as TCustomOrientationSensor; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TOrientationSensorType),integer(LCustomOrientationSensor.SensorType))])); Writeln(Format('Tilt X : %n', [LCustomOrientationSensor.TiltX])); Writeln(Format('Tilt Y : %n', [LCustomOrientationSensor.TiltY])); Writeln(Format('Tilt Z : %n', [LCustomOrientationSensor.TiltZ])); Writeln(Format('Distance X : %n', [LCustomOrientationSensor.DistanceX])); Writeln(Format('Distance Y : %n', [LCustomOrientationSensor.DistanceY])); Writeln(Format('Distance Z : %n', [LCustomOrientationSensor.DistanceZ])); Writeln(Format('Heading X : %n', [LCustomOrientationSensor.HeadingX])); Writeln(Format('Heading Y : %n', [LCustomOrientationSensor.HeadingY])); Writeln(Format('Heading Z : %n', [LCustomOrientationSensor.HeadingZ])); Writeln(Format('Mag. Heading : %n', [LCustomOrientationSensor.MagHeading])); Writeln(Format('True Heading : %n', [LCustomOrientationSensor.TrueHeading])); Writeln(Format('Comp.Heading : %n', [LCustomOrientationSensor.CompMagHeading])); Writeln(Format('Comp True Head : %n', [LCustomOrientationSensor.CompTrueHeading])); end; TSensorCategory.Mechanical : begin LCustomMechanicalSensor:= LSensor as TCustomMechanicalSensor; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TMechanicalSensorType),integer(LCustomMechanicalSensor.SensorType))])); Writeln(Format('Switch State : %s', [BoolToStr(LCustomMechanicalSensor.SwitchState, True)])); Writeln(Format('Switch Array State : %d', [LCustomMechanicalSensor.SwitchArrayState])); Writeln(Format('Multi Value State : %n', [LCustomMechanicalSensor.MultiValueState])); Writeln(Format('Force : %n', [LCustomMechanicalSensor.Force])); Writeln(Format('Abs. Pressure : %n', [LCustomMechanicalSensor.AbsPressure])); Writeln(Format('Gauge Pressure : %n', [LCustomMechanicalSensor.GaugePressure])); Writeln(Format('Strain : %n', [LCustomMechanicalSensor.Strain])); Writeln(Format('Weight : %n', [LCustomMechanicalSensor.Weight])); end; TSensorCategory.Electrical : begin LCustomElectricalSensor:= LSensor as TCustomElectricalSensor; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TElectricalSensorType),integer(LCustomElectricalSensor.SensorType))])); Writeln(Format('Capacitance : %n', [LCustomElectricalSensor.Capacitance])); Writeln(Format('Resistance : %n', [LCustomElectricalSensor.Resistance])); Writeln(Format('Inductance : %n', [LCustomElectricalSensor.Inductance])); Writeln(Format('Current : %n', [LCustomElectricalSensor.Current])); Writeln(Format('Voltage : %n', [LCustomElectricalSensor.Voltage])); Writeln(Format('Power : %n', [LCustomElectricalSensor.Power])); end; TSensorCategory.Biometric : begin LCustomBiometricSensor:= LSensor as TCustomBiometricSensor; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TBiometricSensorType),integer(LCustomBiometricSensor.SensorType))])); Writeln(Format('Human Proximity: %n', [LCustomBiometricSensor.HumanProximity])); Writeln(Format('Human Presense : %s', [BoolToStr(LCustomBiometricSensor.HumanPresense, True)])); Writeln(Format('Touch : %s', [BoolToStr(LCustomBiometricSensor.Touch, True)])); end; TSensorCategory.Scanner : begin LCustomScannerSensor:= LSensor as TCustomScannerSensor; Writeln(Format('Sensor Type : %s', [GetEnumName(TypeInfo(TScannerSensorType),integer(LCustomScannerSensor.SensorType))])); Writeln(Format('Human Proximity: %d', [LCustomScannerSensor.RFIDTag])); Writeln(Format('Barcode Data : %s', [LCustomScannerSensor.BarcodeData])); end; end; Writeln; end else Writeln('Not sensors was found'); LManager.Deactivate; end; begin try EnumerateSensors; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end.
Virtual Sensors
If you don’t have sensors in your machine you can play with these virtual sensors.
Pingback: Utilizando sensores no Delphi | Régys Borges da Silveira
March 22, 2013 at 12:15 am
Thank you, Rodrigo. Bien hecho.
March 22, 2013 at 9:23 am
when i try to run any of the the sensormanager code on a brand new asus vivo tab (windows 8/touch/dock tablet) i get an ‘acces denied’, even with uac turned off and running as admin…any ideas? googling got me zero results (is nobody trying this stuff out, is delphi that dead?).
March 22, 2013 at 10:15 am
Are you enabled the sensors in the Control Panel? Also try making this question in forum like http://stackoverflow.com posting the code which you are using.
March 22, 2013 at 10:29 am
ah, never mind…8i found it…i had to turn on ‘location services’….
December 16, 2013 at 2:56 pm
Hola. Hice un código tan sencillo como el que detallo a continuación, pero no funciona. Obtengo un error de tipo “acces violation”. Estoy usando un Galaxy S4 (rooteado) con Android 4.2.2.
Se les ocurre que puede ser?
Gracias.
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Sensors,
FMX.StdCtrls, FMX.Edit;
type
TForm1 = class(TForm)
btn1: TSpeedButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.btn1Click(Sender: TObject);
var
LCustomEnvironmentalSensor : TCustomEnvironmentalSensor;
begin
Writeln(Format(‘Temperature : %n’, [LCustomEnvironmentalSensor.Temperature]));
Writeln(Format(‘Pressure : %n’, [LCustomEnvironmentalSensor.Pressure]));
Writeln(Format(‘Humidity : %n’, [LCustomEnvironmentalSensor.Humidity]));
end;
end.
December 17, 2013 at 10:39 am
Hola Pablo, el procedimiento Writeln solo debe ser usado en aplicaciones de tipo consola. Asi que debes utilizar otra forma para mostrar la informacion, te recomiendo uses un componente como el TMemo.
December 17, 2013 at 3:40 pm
Hola. Es verdad, corregí el código pero estoy recibiendo otro tipo de error.
Cuando ejecuto el procedimiento recibo como respuesta NAN. No llego a que el sensor me devuelva la temperatura jamás.
procedure TForm1.btn1Click(Sender: TObject);
var
LManager : TSensorManager;
//LCustomEnvironmentalSensor : TCustomEnvironmentalSensor;
LCustomLightSensor : TCustomLightSensor;
LSensors : TSensorArray;
begin
LManager := TSensorManager.Current;
LManager.Activate;
//LSensors := LManager.GetSensorsByCategory(TSensorCategory.Environmental);
LSensors := LManager.GetSensorsByCategory(TSensorCategory.Light);
if Assigned(LSensors) and (Length(LSensors)>0) then
begin
//LCustomEnvironmentalSensor:= LSensors[1] as TCustomEnvironmentalSensor;
LCustomLightSensor:=LSensors[0] as TCustomLightSensor;
//lbl1.Text := FloatToStr(LCustomEnvironmentalSensor.Temperature);LCustomLightSensor.Lux
lbl1.Text := FloatToStr(LCustomLightSensor.Lux);
//Writeln(Format(‘Temperature : %n’, [LCustomEnvironmentalSensor.Temperature]));
//Writeln(Format(‘Pressure : %n’, [LCustomEnvironmentalSensor.Pressure]));
//Writeln(Format(‘Humidity : %n’, [LCustomEnvironmentalSensor.Humidity]));
end
else lbl1.Text := ‘No tiene sensor de Luz!’;
end;
December 27, 2013 at 11:08 am
Pablo, el problema que describes esta fuera del alcance de este articulo. Si aun tienes problemas con el codigo puedes enviarme un proyecto de ejemplo para revisarlo.
December 27, 2013 at 11:15 am
Muchas gracias, Rodrigo. A qué dirección de correo puedo enviarte el código? Nuevamente, muchas gracias por tu tiempo.
Pingback: Sfruttare i sensori dei device - Delphi