Learn How to Create an Actuator and a Controller



In the learn how to create a Raspberry Pi sensor article, we demonstrated how to develop a Pi that is able to sense light, motion and temperature. In the same article, we also discussed how to use C# code to interact with hardware components and capture values sensed. This article will pick up from where the previous article left. The article will focus on demonstrating how to persist captured values in a database, exporting the data, creating an actuator and a controller.

Functionality to support data persistence is available in the Data Clayster library. Data persistence happens via an object database that evaluates the objects that you have designed and creates a database schema that is able to hold the defined objects. The entry point to data persistence is referencing an object as shown below.

internal static ObjectDatabase myDb;

After referencing an object database, information that will be used to connect to the database needs to be provided. One approach used in passing the connection information is adding the connection parameters in a .config file from where the application can read it. This tutorial will demonstrate persisting data to a SQLite database. The parameters that will enable connection to the database are shown below

DB.BackupConnectionString = "Data Source=sensor.db;Version=3;";
DB.BackupProviderName = "Clayster.Library.Data.Providers." +"SQLiteServer.SQLiteServerProvider";

To perform data manipulation activities such as storing, updating, searching and deleting a database, a proxy object is used as shown below. By using a database object we ensure data is not lost when our Raspberry Pi is powered off.

myDb = DB.GetDatabaseProxy ("mySensor");

For our data to be useful we need to go beyond persisting it in a database and be able to export it for consumption by other applications. To fulfill this requirement, the IoT library provides an XML based sensor format. The format orders data by timestamp and for each timestamp it is possible to have string, Boolean, date or enumeration fields. Each field has optional and required metadata associated with it. Required metadata include name and a value of the correct field type. Optional metadata that can be associated with a field include the quality of service and a readout type.

The process of exporting data begins with method call of Start () and ends with a method call of End (). The methods called to initiate and terminate the export process are available in the data export class. The data process export is simplified by calling an intermediate function to retrieve the data from a record object and temporarily store them in another record as an array. The C# code used to retrieve the sensed data is shown below

private static void ExportSensorData (ISensorDataExport Output,
      ReadoutRequest Request)
      Output.Start ();
      lock (synchObject)
	Output.StartNode ("Sensor");
	Export (Output, new Record[]
	      new Record (DateTime.Now, temperatureC, lightPercent,
	    },ReadoutType.MomentaryValues, Request);
	Export (Output, everySec, ReadoutType.HistoricalValuesSecond,
	Export (Output, everyMin, ReadoutType.HistoricalValuesMinute,
	Export (Output, everyHr, ReadoutType.HistoricalValuesHour,
	Export (Output, everyDy, ReadoutType.HistoricalValuesDay,
	Export (Output, everyMon, ReadoutType.HistoricalValuesMonth,
	  Output.EndNode ();
	Output.End ();

Before any data export can happen, there are several checks done on the data. The readout type, the time interval and fields are checked to ensure they conform to what the client requested. Fields that meet the criteria set by the client are exported. The C# code used to check and export fields is shown below.

private static void Export(ISensorDataExport Output,
 IEnumerable<Record> History, ReadoutType Type,
 ReadoutRequest Request)
 if((Request.Types & Type) != 0)
    foreach(Record Rec in History)
      if(!Request.ReportTimestamp (Rec.Timestamp))
      if (Request.ReportField("Temp"))
          1,"C", Type);
        Output.ExportField("Light",Rec.LightPercent, 1, "%",
      if(Request.ReportField ("Motion"))
        Output.ExportField("Motion",Rec.Motion, Type);

In an IoT project, a sensor is used to capture the state of an environment while an actuator utilizes the sensed state to interact with the environment. Because this article is a continuation of the ‘learn how to create a sensor project’, the hardware mentioned here is an addition of previously used hardware. Hardware needed for the actuator includes an alarm and digital outputs, which are connected through GPIO pins. The DigitalOutput class provides a mechanism to interface with digital outputs. To interface with the alarm the SoftwarePwm class will be used. The code used to interact with the outputs is shown below.

private static DigitalOutput executionLed =
new DigitalOutput (8, true);
private static SoftwarePwm alarmOutput = null;
private static Thread alarmThread = null;
private static DigitalOutput[] digitalOutputs =
	new DigitalOutput[]
	new DigitalOutput (19, false),
	new DigitalOutput (24, false),
	new DigitalOutput (27, false),
	new DigitalOutput (22, false),// pin 21 on RaspberryPi R1
	new DigitalOutput (20, false),
	new DigitalOutput (15, false),
	new DigitalOutput (14, false),
	new DigitalOutput (12, false)

A controller is the intelligent link between the sensor and the actuator. The controller processes the data captured by the sensor and communicates its output through the actuator. If the project we have developed is deployed in a home security environment, then an alarm would sound if there is a combination of darkness and movement. Before the controller can do any processing, it needs to acquire the sensed data. The variables shown below will be used to hold the sensed data:

private static bool movement = false;
private static double lightDensity = 0;
private static bool hasValues = false;

Earlier in the article, we demonstrated how to export data in an XML based format. At this stage we need to process the data to detect differences in current and previous data. This processing is implemented using the code shown below.

private static bool UpdateFields(XmlDocument Xml)
FieldBoolean Boolean;
FieldNumeric Numeric;
bool Updated = false;
foreach (Field F in Import.Parse(Xml))
if(F.FieldName == "Motion" &&
(Boolean = F as FieldBoolean) != null)
if(!hasValues || motion != Boolean.Value)
motion = Boolean.Value;
Updated = true;
} else if(F.FieldName == "Light" &&
(Numeric = F as FieldNumeric) != null &&
Numeric.Unit == "%")
if(!hasValues || lightPercent != Numeric.Value)
lightPercent = Numeric.Value;
Updated = true;
return Updated;

In this article, we discussed persisting sensed data into a database, exporting sensed data in an XML based format and using the sensed data to provide intelligence to our IoT project.


Please enter your comment!
Please enter your name here