diff --git a/applications/foobot/foobot_utility.pas b/applications/foobot/foobot_utility.pas
index 4363b306c..643790075 100644
--- a/applications/foobot/foobot_utility.pas
+++ b/applications/foobot/foobot_utility.pas
@@ -41,10 +41,26 @@ const
FOOBOT_DATA_START_FINISH_URL =
'https://api.foobot.io/v2/device/%s/datapoint/%s/%s/%s/';
HIGHLOWMAX = 6;
+ C_TIME = 0;
+ C_PM = 1;
+ C_TMP = 2;
+ C_HUM = 3;
+ C_CO2 = 4;
+ C_VOC = 5;
+ C_ALLPOLLU = 6;
+ C_NONE = 7;
type
TDataFetchType = (dfLast, dfStartEnd);
TSensorType = (st_time, st_pm, st_tmp, st_hum, st_co2, st_voc, st_allpollu);
+ TAlertType = (at_high, at_low);
+
+ TAlertRec = record
+ AlertTriggered: boolean;
+ AlertTime: TDateTime;
+ AlertType: TAlertType;
+ AlertValue: variant;
+ end;
function EncodeStringBase64(const s: string): string;
function FetchAuthenticationKey(aUsername, aUserPassword: string): boolean;
@@ -62,6 +78,7 @@ function FetchFoobotData(DataFetchType: TDataFetchType = dfLast;
// - also populates HighLow arrays
function FoobotDataObjectToArrays: boolean;
+
// Utility functions
function ResetArrays: boolean;
function ResetObjects: boolean;
@@ -70,15 +87,24 @@ function SaveHighLows: boolean;
function LoadHighLows: boolean;
var
+ // Used to fetch server data
HttpClient: TFPHTTPClient;
+ // Holds identity values for multiple Foobots
FoobotIdentityObject: TFoobotIdentityObject;
+ // Holds data for current Foobot
FoobotDataObject: TFoobotDataObject;
+
sAuthenticationKey: string;
- SensorType: TSensorType;
+ SensorType: TSensorType; // st_time, st_pm, st_tmp etc.
+ // Boolean to enable/disable serialisation of HighLows. Default = TRUE
SaveLoadHighLows: boolean;
+ // Boolean to enable/disable Trigger functions
+ UseTriggers: boolean;
+ // Used in data fetch
TheCurrentFoobot: integer;
+ // INIFile located in GetAppConfig(false) folder
HLINI: TIniFile;
- // Easier access to datapoints
+ // Dynamic arrays - easier access to datapoints
// Call FoobotDataObjectToArrays to populate them
FoobotData_time: array of TDateTime;
FoobotData_pm: array of double;
@@ -93,9 +119,17 @@ var
FoobotDataHighTimes: array[0..HIGHLOWMAX] of variant;
FoobotDataLowTimes: array[0..HIGHLOWMAX] of variant;
+ // [0=Low(at_low)..1=High(at_high), C_PM..C_ALLPOLLU]
+ // Dynamic in case of future changes (e.g. more triggers)
+ FooBotTriggerArray: array of array of variant;
+ // Set by FoobotDataObjectToArrays
+ AlertRec: array [C_TIME..C_ALLPOLLU] of TAlertRec;
+ giCount: integer; // used in initialization
+
implementation
function SaveHighLows: boolean;
+ // Save values to an INI data file
var
sFoobotName: string;
begin
@@ -109,47 +143,50 @@ begin
HLINI.WriteString('Foobot', 'CurrentFoobotName', sFoobotName);
// Particulates
- HLINI.WriteFloat(sFoobotName, 'pmHigh', double(FoobotDataHighs[1]));
- HLINI.WriteDateTime(sFoobotName, 'pmHighTime', TDateTime(FoobotDataHighTimes[1]));
- HLINI.WriteFloat(sFoobotName, 'pmLow', double(FoobotDataLows[1]));
- HLINI.WriteDateTime(sFoobotName, 'pmLowTime', TDateTime(FoobotDataLowTimes[1]));
+ HLINI.WriteFloat(sFoobotName, 'pmHigh', double(FoobotDataHighs[C_PM]));
+ HLINI.WriteDateTime(sFoobotName, 'pmHighTime', TDateTime(FoobotDataHighTimes[C_PM]));
+ HLINI.WriteFloat(sFoobotName, 'pmLow', double(FoobotDataLows[C_PM]));
+ HLINI.WriteDateTime(sFoobotName, 'pmLowTime', TDateTime(FoobotDataLowTimes[C_PM]));
// Temp
- HLINI.WriteFloat(sFoobotName, 'tmpHigh', double(FoobotDataHighs[2]));
- HLINI.WriteDateTime(sFoobotName, 'tmpHighTime', TDateTime(FoobotDataHighTimes[2]));
- HLINI.WriteFloat(sFoobotName, 'tmpLow', double(FoobotDataLows[2]));
- HLINI.WriteDateTime(sFoobotName, 'tmpLowTime', TDateTime(FoobotDataLowTimes[2]));
+ HLINI.WriteFloat(sFoobotName, 'tmpHigh', double(FoobotDataHighs[C_TMP]));
+ HLINI.WriteDateTime(sFoobotName, 'tmpHighTime', TDateTime(FoobotDataHighTimes[C_TMP]));
+ HLINI.WriteFloat(sFoobotName, 'tmpLow', double(FoobotDataLows[C_TMP]));
+ HLINI.WriteDateTime(sFoobotName, 'tmpLowTime', TDateTime(FoobotDataLowTimes[C_TMP]));
// Humidity
- HLINI.WriteFloat(sFoobotName, 'humHigh', double(FoobotDataHighs[3]));
- HLINI.WriteDateTime(sFoobotName, 'humHighTime', TDateTime(FoobotDataHighTimes[3]));
- HLINI.WriteFloat(sFoobotName, 'humLow', double(FoobotDataLows[3]));
- HLINI.WriteDateTime(sFoobotName, 'humLowTime', TDateTime(FoobotDataLowTimes[3]));
+ HLINI.WriteFloat(sFoobotName, 'humHigh', double(FoobotDataHighs[C_HUM]));
+ HLINI.WriteDateTime(sFoobotName, 'humHighTime', TDateTime(FoobotDataHighTimes[C_HUM]));
+ HLINI.WriteFloat(sFoobotName, 'humLow', double(FoobotDataLows[C_HUM]));
+ HLINI.WriteDateTime(sFoobotName, 'humLowTime', TDateTime(FoobotDataLowTimes[C_HUM]));
// CO2
- HLINI.WriteInteger(sFoobotName, 'co2High', integer(FoobotDataHighs[4]));
- HLINI.WriteDateTime(sFoobotName, 'co2HighTime', TDateTime(FoobotDataHighTimes[4]));
- HLINI.WriteInteger(sFoobotName, 'co2Low', integer(FoobotDataLows[4]));
- HLINI.WriteDateTime(sFoobotName, 'co2LowTime', TDateTime(FoobotDataLowTimes[4]));
+ HLINI.WriteInteger(sFoobotName, 'co2High', integer(FoobotDataHighs[C_CO2]));
+ HLINI.WriteDateTime(sFoobotName, 'co2HighTime', TDateTime(FoobotDataHighTimes[C_CO2]));
+ HLINI.WriteInteger(sFoobotName, 'co2Low', integer(FoobotDataLows[C_CO2]));
+ HLINI.WriteDateTime(sFoobotName, 'co2LowTime', TDateTime(FoobotDataLowTimes[C_CO2]));
// Volatile Compounds
- HLINI.WriteInteger(sFoobotName, 'vocHigh', integer(FoobotDataHighs[5]));
- HLINI.WriteDateTime(sFoobotName, 'vocHighTime', TDateTime(FoobotDataHighTimes[5]));
- HLINI.WriteInteger(sFoobotName, 'vocLow', integer(FoobotDataLows[5]));
- HLINI.WriteDateTime(sFoobotName, 'vocLowTime', TDateTime(FoobotDataLowTimes[5]));
+ HLINI.WriteInteger(sFoobotName, 'vocHigh', integer(FoobotDataHighs[C_VOC]));
+ HLINI.WriteDateTime(sFoobotName, 'vocHighTime', TDateTime(FoobotDataHighTimes[C_VOC]));
+ HLINI.WriteInteger(sFoobotName, 'vocLow', integer(FoobotDataLows[C_VOC]));
+ HLINI.WriteDateTime(sFoobotName, 'vocLowTime', TDateTime(FoobotDataLowTimes[C_VOC]));
// All Pollution
- HLINI.WriteFloat(sFoobotName, 'allpolluHigh', double(FoobotDataHighs[6]));
- HLINI.WriteDateTime(sFoobotName, 'allpolluHighTime', TDateTime(FoobotDataHighTimes[6]));
- HLINI.WriteFloat(sFoobotName, 'allpolluLow', double(FoobotDataLows[6]));
- HLINI.WriteDateTime(sFoobotName, 'allpolluLowTime', TDateTime(FoobotDataLowTimes[6]));
- Result:=TRUE;
+ HLINI.WriteFloat(sFoobotName, 'allpolluHigh', double(FoobotDataHighs[C_ALLPOLLU]));
+ HLINI.WriteDateTime(sFoobotName, 'allpolluHighTime',
+ TDateTime(FoobotDataHighTimes[C_ALLPOLLU]));
+ HLINI.WriteFloat(sFoobotName, 'allpolluLow', double(FoobotDataLows[C_ALLPOLLU]));
+ HLINI.WriteDateTime(sFoobotName, 'allpolluLowTime',
+ TDateTime(FoobotDataLowTimes[C_ALLPOLLU]));
+ Result := True;
end;
function LoadHighLows: boolean;
+ // Load values from an INI data file
var
sFoobotName: string;
begin
if SaveLoadHighLows = False then
- begin
- ShowMessage('Unable to load All-Time stats');
- Exit(False);
- end;
+ begin
+ ShowMessage('Unable to load All-Time stats');
+ Exit(False);
+ end;
sFoobotName := FoobotIdentityObject.FoobotIdentityList[TheCurrentFoobot].Name;
if not Assigned(HLINI) then
HLINI := TIniFile.Create(ChangeFileExt(GetAppConfigFile(False), '.ini'));
@@ -158,47 +195,55 @@ begin
Exit(False);
// Particulates
- FoobotDataHighs[1] := HLINI.ReadFloat(sFoobotName, 'pmHigh', 0);
- FoobotDataHighTimes[1] := HLINI.ReadDateTime(sFoobotName, 'pmHighTime', Now);
- FoobotDataLows[1] := HLINI.ReadFloat(sFoobotName, 'pmLow', 0);
- FoobotDataLowTimes[1] := HLINI.ReadDateTime(sFoobotName, 'pmLowTime', Now);
+ FoobotDataHighs[C_PM] := HLINI.ReadFloat(sFoobotName, 'pmHigh', 0);
+ FoobotDataHighTimes[C_PM] := HLINI.ReadDateTime(sFoobotName, 'pmHighTime', Now);
+ FoobotDataLows[C_PM] := HLINI.ReadFloat(sFoobotName, 'pmLow', 0);
+ FoobotDataLowTimes[C_PM] := HLINI.ReadDateTime(sFoobotName, 'pmLowTime', Now);
// Temp
- FoobotDataHighs[2] := HLINI.ReadFloat(sFoobotName, 'tmpHigh', 0);
- FoobotDataHighTimes[2] := HLINI.ReadDateTime(sFoobotName, 'tmpHighTime', Now);
- FoobotDataLows[2] := HLINI.ReadFloat(sFoobotName, 'tmpLow', 0);
- FoobotDataLowTimes[2] := HLINI.ReadDateTime(sFoobotName, 'tmpLowTime', Now);
+ FoobotDataHighs[C_TMP] := HLINI.ReadFloat(sFoobotName, 'tmpHigh', 0);
+ FoobotDataHighTimes[C_TMP] := HLINI.ReadDateTime(sFoobotName, 'tmpHighTime', Now);
+ FoobotDataLows[C_TMP] := HLINI.ReadFloat(sFoobotName, 'tmpLow', 0);
+ FoobotDataLowTimes[C_TMP] := HLINI.ReadDateTime(sFoobotName, 'tmpLowTime', Now);
// Humidity
- FoobotDataHighs[3] := HLINI.ReadFloat(sFoobotName, 'humHigh', 0);
- FoobotDataHighTimes[3] := HLINI.ReadDateTime(sFoobotName, 'humHighTime', Now);
- FoobotDataLows[3] := HLINI.ReadFloat(sFoobotName, 'humLow', 0);
- FoobotDataLowTimes[3] := HLINI.ReadDateTime(sFoobotName, 'humLowTime', Now);
+ FoobotDataHighs[C_HUM] := HLINI.ReadFloat(sFoobotName, 'humHigh', 0);
+ FoobotDataHighTimes[C_HUM] := HLINI.ReadDateTime(sFoobotName, 'humHighTime', Now);
+ FoobotDataLows[C_HUM] := HLINI.ReadFloat(sFoobotName, 'humLow', 0);
+ FoobotDataLowTimes[C_HUM] := HLINI.ReadDateTime(sFoobotName, 'humLowTime', Now);
// CO2
- FoobotDataHighs[4] := HLINI.ReadInteger(sFoobotName, 'co2High', 0);
- FoobotDataHighTimes[4] := HLINI.ReadDateTime(sFoobotName, 'co2HighTime', Now);
- FoobotDataLows[4] := HLINI.ReadInteger(sFoobotName, 'co2Low', 0);
- FoobotDataLowTimes[4] := HLINI.ReadDateTime(sFoobotName, 'co2LowTime', Now);
+ FoobotDataHighs[C_CO2] := HLINI.ReadInteger(sFoobotName, 'co2High', 0);
+ FoobotDataHighTimes[C_CO2] := HLINI.ReadDateTime(sFoobotName, 'co2HighTime', Now);
+ FoobotDataLows[C_CO2] := HLINI.ReadInteger(sFoobotName, 'co2Low', 0);
+ FoobotDataLowTimes[C_CO2] := HLINI.ReadDateTime(sFoobotName, 'co2LowTime', Now);
// Volatile Compounds
- FoobotDataHighs[5] := HLINI.ReadInteger(sFoobotName, 'vocHigh', 0);
- FoobotDataHighTimes[5] := HLINI.ReadDateTime(sFoobotName, 'vocHighTime', Now);
- FoobotDataLows[5] := HLINI.ReadInteger(sFoobotName, 'vocLow', 0);
- FoobotDataLowTimes[5] := HLINI.ReadDateTime(sFoobotName, 'vocLowTime', Now);
+ FoobotDataHighs[C_VOC] := HLINI.ReadInteger(sFoobotName, 'vocHigh', 0);
+ FoobotDataHighTimes[C_VOC] := HLINI.ReadDateTime(sFoobotName, 'vocHighTime', Now);
+ FoobotDataLows[C_VOC] := HLINI.ReadInteger(sFoobotName, 'vocLow', 0);
+ FoobotDataLowTimes[C_VOC] := HLINI.ReadDateTime(sFoobotName, 'vocLowTime', Now);
// All Pollution
- FoobotDataHighs[6] := HLINI.ReadFloat(sFoobotName, 'allpolluHigh', 0);
- FoobotDataHighTimes[6] := HLINI.ReadDateTime(sFoobotName, 'allpolluHighTime', Now);
- FoobotDataLows[6] := HLINI.ReadFloat(sFoobotName, 'allpolluLow', 0);
- FoobotDataLowTimes[6] := HLINI.ReadDateTime(sFoobotName, 'allpolluLowTime', Now);
- Result:=TRUE;
+ FoobotDataHighs[C_ALLPOLLU] := HLINI.ReadFloat(sFoobotName, 'allpolluHigh', 0);
+ FoobotDataHighTimes[C_ALLPOLLU] :=
+ HLINI.ReadDateTime(sFoobotName, 'allpolluHighTime', Now);
+ FoobotDataLows[C_ALLPOLLU] := HLINI.ReadFloat(sFoobotName, 'allpolluLow', 0);
+ FoobotDataLowTimes[C_ALLPOLLU] :=
+ HLINI.ReadDateTime(sFoobotName, 'allpolluLowTime', Now);
+ Result := True;
end;
-// ToDo: Multiple Foobots?
+// Function to make the Foobot data accessible
+// Also sets the HighLow array values
+// Also sets triggers
+{
+TAlertRec = Record
+ Triggered:Boolean;
+ AlertTime:TDateTime;
+ AlertType:TAlertType;
+ AlertValue:Variant;
+end;
+}
function FoobotDataObjectToArrays: boolean;
var
J, K: integer;
Mydatapoint: variant;
- {
- dtDate, dtStart, dtEnd: TDateTime;
- sStart, sEnd: string;
- }
iUnixSecs: int64;
// ========= Internal routines start ===========
procedure SetHigh(iMember: integer; aValue: variant; aDateTime: TDateTime);
@@ -207,6 +252,21 @@ var
begin
FoobotDataHighs[iMember] := aValue;
FoobotDataHighTimes[iMember] := aDateTime;
+ SaveHighLows;
+ end;
+ if ((UseTriggers = True) and (FooBotTriggerArray[1, iMember] <> 0)) then
+ begin
+ // Process High Trigger
+ // Sets AlertRec record
+ if (aValue > FooBotTriggerArray[1, iMember]) then
+ begin
+ AlertRec[iMember].AlertTriggered := True;
+ AlertRec[iMember].AlertTime := aDateTime;
+ AlertRec[iMember].AlertType := at_high;
+ AlertRec[iMember].AlertValue := aValue;
+ end
+ else
+ AlertRec[iMember].AlertTriggered := False;
end;
end;
@@ -216,6 +276,21 @@ var
begin
FoobotDataLows[iMember] := aValue;
FoobotDataLowTimes[iMember] := aDateTime;
+ SaveHighLows;
+ end;
+ if ((UseTriggers = True) and (FooBotTriggerArray[0, iMember] <> 0)) then
+ begin
+ // Process Low Trigger
+ // Sets AlertRec record
+ if (aValue < FooBotTriggerArray[1, iMember]) then
+ begin
+ AlertRec[iMember].AlertTriggered := True;
+ AlertRec[iMember].AlertTime := aDateTime;
+ AlertRec[iMember].AlertType := at_low;
+ AlertRec[iMember].AlertValue := aValue;
+ end
+ else
+ AlertRec[iMember].AlertTriggered := False;
end;
end;
// ========== Internal routines end =============
@@ -238,60 +313,87 @@ begin
begin
Mydatapoint := FoobotDataObject.datapoints[K][J];
case J of
- 0: // First field is a DateTime
+ C_TIME: // First field is a DateTime
begin
iUnixSecs := int64(Mydatapoint);
SetLength(FoobotData_time, K + 1);
FoobotData_time[K] := UnixToDateTime(iUnixSecs);
end;
- 1: // Particulate matter
+ C_PM: // Particulate matter
begin
SetLength(FoobotData_pm, K + 1);
FoobotData_pm[K] := double(MyDataPoint);
SetHigh(J, FoobotData_pm[K], FoobotData_time[K]);
SetLow(J, FoobotData_pm[K], FoobotData_time[K]);
end;
- 2: // Temperature
+ C_TMP: // Temperature
begin
SetLength(FoobotData_tmp, K + 1);
FoobotData_tmp[K] := double(MyDataPoint);
SetHigh(J, FoobotData_tmp[K], FoobotData_time[K]);
SetLow(J, FoobotData_tmp[K], FoobotData_time[K]);
end;
- 3: // Humidity
+ C_HUM: // Humidity
begin
SetLength(FoobotData_hum, K + 1);
FoobotData_hum[K] := double(MyDataPoint);
SetHigh(J, FoobotData_hum[K], FoobotData_time[K]);
SetLow(J, FoobotData_hum[K], FoobotData_time[K]);
end;
- 4: // CO2
+ C_CO2: // CO2
begin
SetLength(FoobotData_co2, K + 1);
FoobotData_co2[K] := integer(MyDataPoint);
SetHigh(J, FoobotData_co2[K], FoobotData_time[K]);
SetLow(J, FoobotData_co2[K], FoobotData_time[K]);
end;
- 5: // Volatile compounds
+ C_VOC: // Volatile compounds
begin
SetLength(FoobotData_voc, K + 1);
FoobotData_voc[K] := integer(MyDataPoint);
SetHigh(J, FoobotData_voc[K], FoobotData_time[K]);
SetLow(J, FoobotData_voc[K], FoobotData_time[K]);
end;
- 6: // All Pollution
+ C_ALLPOLLU: // All Pollution
begin
SetLength(FoobotData_allpollu, K + 1);
FoobotData_allpollu[K] := double(MyDataPoint);
SetHigh(J, FoobotData_allpollu[K], FoobotData_time[K]);
SetLow(J, FoobotData_allpollu[K], FoobotData_time[K]);
end;
+ else raise Exception.Create('Error in FoobotDataObjectToArrays Case');
end; // of Case
end;
end;
- SaveHighLows;
+
end;
+
+function SetHighTrigger(const aSensor: TSensorType; const aValue: variant): boolean;
+begin
+ Result := False;
+ if UseTriggers = False then
+ Exit;
+ if aValue <> FooBotTriggerArray[1, Ord(aSensor)] then
+ begin
+ FooBotTriggerArray[1, Ord(aSensor)] := aValue;
+ Result := True;
+ end;
+end;
+
+function SetLowTrigger(const aSensor: TSensorType; const aValue: variant): boolean;
+begin
+ Result := False;
+ if UseTriggers = False then
+ Exit;
+ if aValue <> FooBotTriggerArray[0, Ord(aSensor)] then
+ begin
+ FooBotTriggerArray[0, Ord(aSensor)] := aValue;
+ Result := True;
+ end;
+end;
+
+// Data cleaning functions
function ResetHighLows: boolean;
var
iCount: integer;
@@ -341,6 +443,7 @@ begin
end;
end;
+// Authentication functions
function EncodeStringBase64(const s: string): string;
var
@@ -395,10 +498,12 @@ begin
Result := True;
end;
finally
+ // Empty
end;
end;
+// This function must succeed before calling FetchFoobotData
function FetchFoobotIdentity(aUsername, aSecretKey: string): boolean;
var
sUserNameURL: string;
@@ -448,6 +553,7 @@ begin
end;
end;
+// Function FetchFoobotIdentity must be called before this one
function FetchFoobotData(DataFetchType: TDataFetchType;
iCurrentFoobot, iLastIntervalSeconds, iLastAverageBySeconds: integer;
iStartTimeSeconds, iEndTimeSeconds: int64; aSecretKey: string): boolean;
@@ -532,8 +638,17 @@ initialization
HttpClient := TFPHTTPClient.Create(nil);
FoobotIdentityObject := TFoobotIdentityObject.Create;
FoobotDataObject := TFoobotDataObject.Create;
- SaveLoadHighLows := True;
TheCurrentFoobot := 0;
+ SetLength(FooBotTriggerArray, 2, Succ(C_ALLPOLLU));
+ SaveLoadHighLows := True; // Default
+ UseTriggers := False; // Defaul
+ for giCount := C_PM to C_ALLPOLLU do
+ begin
+ AlertRec[giCount].AlertTriggered := False;
+ AlertRec[giCount].AlertTime := Now;
+ AlertRec[giCount].AlertType := at_low;
+ AlertRec[giCount].AlertValue := 0;
+ end;
end;
finalization
@@ -550,6 +665,7 @@ finalization
SetLength(FoobotData_co2, 0);
SetLength(FoobotData_voc, 0);
SetLength(FoobotData_allpollu, 0);
+ SetLength(FooBotTriggerArray, 0, 0);
end;
end.
diff --git a/applications/foobot/latest_stable/foobot_objects.pas b/applications/foobot/latest_stable/foobot_objects.pas
index 3d10689a6..66e6e14cd 100644
--- a/applications/foobot/latest_stable/foobot_objects.pas
+++ b/applications/foobot/latest_stable/foobot_objects.pas
@@ -1,5 +1,5 @@
unit foobot_objects;
-{ Objects for Foobot Interrogator
+{ Objects for Foobot Lazarus
Copyright (C)2016 Gordon Bamber minsadorada@charcodelvalle.com
diff --git a/applications/foobot/monitor/foobotmonitor.lpi b/applications/foobot/monitor/foobotmonitor.lpi
index 600bd236c..3cec7719c 100644
--- a/applications/foobot/monitor/foobotmonitor.lpi
+++ b/applications/foobot/monitor/foobotmonitor.lpi
@@ -23,6 +23,7 @@
+
@@ -236,7 +237,7 @@
-
+
@@ -282,6 +283,13 @@
+
+
+
+
+
+
+
@@ -322,9 +330,6 @@
-
-
-
diff --git a/applications/foobot/monitor/foobotmonitor.lpr b/applications/foobot/monitor/foobotmonitor.lpr
index 8b8daca27..02d29f2e0 100644
--- a/applications/foobot/monitor/foobotmonitor.lpr
+++ b/applications/foobot/monitor/foobotmonitor.lpr
@@ -15,7 +15,8 @@ uses
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
- Forms, usplash, tachartlazaruspkg, umainform, uconfigform, foobot_sensors
+ Forms, usplash, tachartlazaruspkg, umainform, uconfigform, foobot_sensors,
+ utriggersform
{ you can add units after this };
{$R *.res}
@@ -29,6 +30,7 @@ begin
Application.ProcessMessages; // process splash paint message
Application.CreateForm(Tmainform, mainform);
Application.CreateForm(Tconfigform, configform);
+ Application.CreateForm(Ttriggersform, triggersform);
Application.Run;
end.
diff --git a/applications/foobot/monitor/foobotmonitor.lps b/applications/foobot/monitor/foobotmonitor.lps
index 802bd9ebd..3f180fc99 100644
--- a/applications/foobot/monitor/foobotmonitor.lps
+++ b/applications/foobot/monitor/foobotmonitor.lps
@@ -3,14 +3,14 @@
-
-
+
+
-
-
-
+
+
+
@@ -19,10 +19,9 @@
-
-
-
-
+
+
+
@@ -32,10 +31,10 @@
-
+
-
+
@@ -45,7 +44,7 @@
-
+
@@ -54,15 +53,16 @@
-
+
-
-
-
-
+
+
+
+
+
@@ -72,15 +72,15 @@
-
+
-
+
-
+
@@ -89,297 +89,314 @@
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
+
+
+
+
diff --git a/applications/foobot/monitor/foobotmonitor.res b/applications/foobot/monitor/foobotmonitor.res
index 472d06b80..0cce42ae6 100644
Binary files a/applications/foobot/monitor/foobotmonitor.res and b/applications/foobot/monitor/foobotmonitor.res differ
diff --git a/applications/foobot/monitor/splashimage.jpg b/applications/foobot/monitor/splashimage.jpg
index a19422e54..e80513959 100644
Binary files a/applications/foobot/monitor/splashimage.jpg and b/applications/foobot/monitor/splashimage.jpg differ
diff --git a/applications/foobot/monitor/umainform.lfm b/applications/foobot/monitor/umainform.lfm
index 81a92dd4d..cb7b61644 100644
--- a/applications/foobot/monitor/umainform.lfm
+++ b/applications/foobot/monitor/umainform.lfm
@@ -492,6 +492,20 @@ object mainform: Tmainform
Caption = 'Reset All-time Highs/Lows'
OnClick = mnu_optionsResetHighsLowsClick
end
+ object mnu_optionsFoobotTriggers: TMenuItem
+ Caption = 'Foobot Triggers...'
+ OnClick = mnu_optionsFoobotTriggersClick
+ object mnu_options_triggersSetTriggers: TMenuItem
+ Caption = 'Set Trigger Values...'
+ OnClick = mnu_options_triggersSetTriggersClick
+ end
+ object mnu_options_triggersActivateTriggers: TMenuItem
+ Caption = 'Set Triggers On'
+ Enabled = False
+ RadioItem = True
+ OnClick = mnu_options_triggersActivateTriggersClick
+ end
+ end
end
object mnu_foobot: TMenuItem
Caption = '&Foobot'
diff --git a/applications/foobot/monitor/umainform.pas b/applications/foobot/monitor/umainform.pas
index c9195668f..dfbb27cd9 100644
--- a/applications/foobot/monitor/umainform.pas
+++ b/applications/foobot/monitor/umainform.pas
@@ -40,7 +40,7 @@ interface
uses
SysUtils, TAGraph, TAIntervalSources, TASeries, foobot_sensors,
Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, Menus, lclIntf,
- foobot_utility, uCryptIni, dateutils, uconfigform;
+ foobot_utility, uCryptIni, dateutils, uconfigform,utriggersform, Classes;
const
// Timer milliseconds
@@ -123,6 +123,9 @@ type
lbl_voclow: TLabel;
lbl_allpollulow: TLabel;
MainMenu1: TMainMenu;
+ mnu_options_triggersActivateTriggers: TMenuItem;
+ mnu_options_triggersSetTriggers: TMenuItem;
+ mnu_optionsFoobotTriggers: TMenuItem;
mnu_foobot: TMenuItem;
mnu_optionsDisplayRedLines: TMenuItem;
mnu_optionsDisplayYellowLines: TMenuItem;
@@ -166,7 +169,10 @@ type
procedure mnu_optionsOnlineHelpClick(Sender: TObject);
procedure mnu_optionsResetHighsLowsClick(Sender: TObject);
procedure mnu_optionsSaveHighLowsClick(Sender: TObject);
+ procedure mnu_optionsFoobotTriggersClick(Sender: TObject);
procedure mnu_optionsTakeReadingNowClick(Sender: TObject);
+ procedure mnu_options_triggersActivateTriggersClick(Sender: TObject);
+ procedure mnu_options_triggersSetTriggersClick(Sender: TObject);
procedure mnu_SampleEvery1HourClick(Sender: TObject);
procedure mnu_SampleEvery24HoursClick(Sender: TObject);
procedure mnu_SampleEvery2HoursClick(Sender: TObject);
@@ -240,6 +246,7 @@ begin
TrayIcon1.Hint := Application.Title;
DateTimeIntervalChartSource1.DateTimeFormat := 'hh:nn';
LoadConfig;
+ {$IFDEF DEBUGMODE}UseTriggers:=FALSE;{$ENDIF}
end;
procedure Tmainform.FormActivate(Sender: TObject);
@@ -517,7 +524,7 @@ begin
exit;
ResetHighLows;
SaveHighLows;
- for iCount := 1 to 6 do
+ for iCount := C_PM to C_ALLPOLLU do
UpdateHighLow(iCount);
end;
@@ -527,6 +534,10 @@ begin
INI.WriteBool('Foobot', 'SaveLoadHighLows', SaveLoadHighLows);
end;
+procedure Tmainform.mnu_optionsFoobotTriggersClick(Sender: TObject);
+begin
+end;
+
procedure Tmainform.mnu_optionsTakeReadingNowClick(Sender: TObject);
begin
mainform.Cursor := crHourGlass;
@@ -537,6 +548,25 @@ begin
mainform.Cursor := crDefault;
end;
+procedure Tmainform.mnu_options_triggersActivateTriggersClick(Sender: TObject);
+begin
+ mnu_options_triggersActivateTriggers.Checked:= NOT mnu_options_triggersActivateTriggers.Checked;
+ UseTriggers:=mnu_options_triggersActivateTriggers.Checked;
+ If UseTriggers then
+ mnu_options_triggersActivateTriggers.Caption:='Set Triggers Off'
+ else
+ mnu_options_triggersActivateTriggers.Caption:='Set Triggers On';
+end;
+
+procedure Tmainform.mnu_options_triggersSetTriggersClick(Sender: TObject);
+begin
+ triggersform.ShowModal;
+ If triggersform.ModalResult = mrCancel then
+ ShowMessage('Cancel')
+ else
+ mnu_options_triggersActivateTriggers.Enabled:=TRUE;
+end;
+
procedure Tmainform.mnu_SampleEveryHalfHourClick(Sender: TObject);
begin
tmr_foobot.Enabled := False;
@@ -650,7 +680,7 @@ end;
procedure Tmainform.UpdateHighLow(SensorNumber: integer);
begin
case SensorNumber of
- 1:
+ C_PM:
begin
lbl_pmhigh.Caption := Format('High: %f %s',
[double(FoobotDataHighs[SensorNumber]), FoobotDataObject.Units[SensorNumber]]) +
@@ -661,7 +691,7 @@ begin
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
- 2:
+ C_TMP:
begin
lbl_tmphigh.Caption := Format('High: %f %s',
[double(FoobotDataHighs[SensorNumber]), FoobotDataObject.Units[SensorNumber]]) +
@@ -672,7 +702,7 @@ begin
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
- 3:
+ C_HUM:
begin
lbl_humhigh.Caption := Format('High: %f %s',
[double(FoobotDataHighs[SensorNumber]), FoobotDataObject.Units[SensorNumber]]) +
@@ -683,7 +713,7 @@ begin
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
- 4:
+ C_CO2:
begin
lbl_co2high.Caption := Format('High: %f %s',
[double(FoobotDataHighs[SensorNumber]), FoobotDataObject.Units[SensorNumber]]) +
@@ -694,7 +724,7 @@ begin
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
- 5:
+ C_VOC:
begin
lbl_vochigh.Caption := Format('High: %f %s',
[double(FoobotDataHighs[SensorNumber]), FoobotDataObject.Units[SensorNumber]]) +
@@ -705,7 +735,7 @@ begin
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
- 6:
+ C_ALLPOLLU:
begin
lbl_allpolluhigh.Caption :=
Format('High: %f %s', [double(FoobotDataHighs[SensorNumber]),
@@ -724,32 +754,32 @@ begin
with Sender do
begin
case SensorNumber of
- 1:
+ C_PM:
begin
Value := FoobotData_pm[0];
Caption := Format('PM (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
- 2:
+ C_TMP:
begin
Value := FoobotData_tmp[0];
Caption := Format('Temp (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
- 3:
+ C_HUM:
begin
Value := FoobotData_hum[0];
Caption := Format('Hum. (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
- 4:
+ C_CO2:
begin
Value := FoobotData_co2[0];
Caption := Format('CO2 (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
- 5:
+ C_VOC:
begin
Value := FoobotData_voc[0];
Caption := Format('VOC (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
- 6:
+ C_ALLPOLLU:
begin
Value := FoobotData_allpollu[0];
Caption := Format('All (%s): ', [FoobotDataObject.Units[SensorNumber]]);
@@ -774,18 +804,33 @@ begin
mainform.Caption := Format('Foobot "%s" - Last reading: ',
[FoobotIdentityObject.FoobotIdentityList[0].Name]) +
FormatDateTime('dd/mm/yyyy - tt', FoobotData_time[0]);
- UpdateGuage(as_pm, 1);
- UpdateGuage(as_tmp, 2);
- UpdateGuage(as_hum, 3);
- UpdateGuage(as_co2, 4);
- UpdateGuage(as_voc, 5);
- UpdateGuage(as_allpollu, 6);
+ UpdateGuage(as_pm, C_PM);
+ UpdateGuage(as_tmp, C_TMP);
+ UpdateGuage(as_hum, C_HUM);
+ UpdateGuage(as_co2, C_CO2);
+ UpdateGuage(as_voc, C_VOC);
+ UpdateGuage(as_allpollu, C_ALLPOLLU);
if not bDisplayGuagesOnly then
begin
for iCount := 1 to 6 do
UpdateHighLow(iCount);
end;
GraphCurrentReading;
+
+ // Process Trigger Alerts
+ If UseTriggers then
+ For iCount:=C_PM to C_ALLPOLLU do
+ If AlertRec[iCount].AlertTriggered then
+ If AlertRec[iCount].AlertType = at_high then
+ begin
+ ShowMessageFmt('High alert member %d (value %f) exceeded',
+ [iCount,Double(AlertRec[iCount].AlertValue)]);
+ end
+ else
+ begin
+ ShowMessageFmt('Low alert member %d (value %f) exceeded',
+ [iCount,Double(AlertRec[iCount].AlertValue)]);
+ end;
end;
end;
@@ -799,6 +844,7 @@ end;
procedure Tmainform.GraphCurrentReading;
begin
+ {$IFDEF DEBUGMODE}Exit;{$ENDIF}
lineseries_pm.AddXY(FoobotData_time[0],
AsPercent(FoobotData_pm[0], as_pm.ValueMin, as_pm.ValueMax));
lineseries_tmp.AddXY(FoobotData_time[0], AsPercent(FoobotData_tmp[0],
@@ -820,6 +866,7 @@ var
iCount: integer;
iStartSeconds, iEndSeconds: int64;
begin
+ {$IFDEF DEBUGMODE}Exit;{$ENDIF}
iEndSeconds := DateTimeToUnix(Now) - 3600;
iStartSeconds := iEndSeconds - (2 * (24 * 3600)); // 49 hours before Now
grp_chart.Caption := Format('History from %s',
diff --git a/applications/foobot/monitor/usplash.lfm b/applications/foobot/monitor/usplash.lfm
index e65098e72..c4a3b7a1d 100644
--- a/applications/foobot/monitor/usplash.lfm
+++ b/applications/foobot/monitor/usplash.lfm
@@ -1,12 +1,12 @@
object splashform: Tsplashform
Left = 596
- Height = 480
+ Height = 484
Top = 136
- Width = 790
+ Width = 794
BorderStyle = bsNone
Caption = 'splashform'
- ClientHeight = 480
- ClientWidth = 790
+ ClientHeight = 484
+ ClientWidth = 794
DefaultMonitor = dmDesktop
FormStyle = fsStayOnTop
OnCreate = FormCreate
@@ -16,9 +16,9 @@ object splashform: Tsplashform
Scaled = True
object img: TImage
Left = 0
- Height = 480
+ Height = 484
Top = 0
- Width = 790
+ Width = 794
Align = alClient
Stretch = True
Transparent = True
diff --git a/applications/foobot/monitor/usplash.pas b/applications/foobot/monitor/usplash.pas
index aab384853..f893b3e9c 100644
--- a/applications/foobot/monitor/usplash.pas
+++ b/applications/foobot/monitor/usplash.pas
@@ -35,7 +35,7 @@ begin
jpg:=TJPEGImage.Create;
try
jpg.LoadFromResourceName(HInstance,'SPLASHIMAGE');
- Img.Canvas.Draw(0,0,jpg);
+ img.Canvas.Draw(0,0,jpg);
finally
jpg.Free;
end;
diff --git a/applications/foobot/monitor/utriggersform.lfm b/applications/foobot/monitor/utriggersform.lfm
new file mode 100644
index 000000000..029982fbc
--- /dev/null
+++ b/applications/foobot/monitor/utriggersform.lfm
@@ -0,0 +1,49 @@
+object triggersform: Ttriggersform
+ Left = 546
+ Height = 484
+ Top = 142
+ Width = 794
+ BorderIcons = [biSystemMenu]
+ BorderStyle = bsSingle
+ Caption = 'triggersform'
+ ClientHeight = 484
+ ClientWidth = 794
+ DefaultMonitor = dmDesktop
+ FormStyle = fsStayOnTop
+ OnCreate = FormCreate
+ Position = poWorkAreaCenter
+ ShowInTaskBar = stNever
+ LCLVersion = '1.7'
+ Scaled = True
+ object grp_main: TGroupBox
+ Left = 0
+ Height = 424
+ Top = 0
+ Width = 794
+ Align = alTop
+ Caption = 'Foobot Triggers'
+ TabOrder = 0
+ end
+ object cmd_OK: TBitBtn
+ Left = 360
+ Height = 30
+ Top = 440
+ Width = 75
+ Default = True
+ DefaultCaption = True
+ Kind = bkOK
+ ModalResult = 1
+ TabOrder = 1
+ end
+ object cmd_cancel: TBitBtn
+ Left = 704
+ Height = 30
+ Top = 440
+ Width = 75
+ Cancel = True
+ DefaultCaption = True
+ Kind = bkCancel
+ ModalResult = 2
+ TabOrder = 2
+ end
+end
diff --git a/applications/foobot/monitor/utriggersform.pas b/applications/foobot/monitor/utriggersform.pas
new file mode 100644
index 000000000..946382ac7
--- /dev/null
+++ b/applications/foobot/monitor/utriggersform.pas
@@ -0,0 +1,42 @@
+unit utriggersform;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
+ Buttons;
+
+type
+
+ { Ttriggersform }
+
+ Ttriggersform = class(TForm)
+ cmd_cancel: TBitBtn;
+ cmd_OK: TBitBtn;
+ grp_main: TGroupBox;
+ procedure FormCreate(Sender: TObject);
+ private
+
+ public
+
+ end;
+
+var
+ triggersform: Ttriggersform;
+
+implementation
+Uses umainform;
+{$R *.lfm}
+
+{ Ttriggersform }
+
+procedure Ttriggersform.FormCreate(Sender: TObject);
+begin
+ Icon:=Application.Icon;
+ Caption:=Application.Title + ' - Set Triggers';
+end;
+
+end.
+