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.
- GPSDirect NMEA Sensor Driver for Windows 7
- Geosense for Windows Sensor
- Microsoft Virtual Light Sensor included in the Windows SDK