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.
-33.636934
-70.679350