diff --git a/applications/foobot/foobot_utility.pas b/applications/foobot/foobot_utility.pas index cd1e4e609..3f014d6ed 100644 --- a/applications/foobot/foobot_utility.pas +++ b/applications/foobot/foobot_utility.pas @@ -52,13 +52,16 @@ const type TDataFetchType = (dfLast, dfStartEnd); // FetchFoobotData + + // Unused TSensorType = (st_time, st_pm, st_tmp, st_hum, st_co2, st_voc, st_allpollu); // Unused + // Unused TAlertType = (at_high, at_low); // TAlertRec TAlertRec = record AlertTriggered: boolean; AlertTime: TDateTime; - AlertType: TAlertType; + AlertType: Integer; AlertValue: variant; end; @@ -78,10 +81,12 @@ function FetchFoobotData(DataFetchType: TDataFetchType = dfLast; // - also populates HighLow arrays function FoobotDataObjectToArrays: boolean; -// Sets internal FooBotTriggerArray which can be tested against in FoobotDataObjectToArrays +// Gets/Sets internal FooBotTriggerArray which can be tested against in FoobotDataObjectToArrays // aSensor use consts: C_PM,C_TMP etc. function SetHighTrigger(const aSensor: integer; const aValue: variant): boolean; function SetLowTrigger(const aSensor: integer; const aValue: variant): boolean; +function GetHighTrigger(Const aSensor:Integer):Variant; +function GetLowTrigger(Const aSensor:Integer):Variant; // Utility functions function ResetArrays: boolean; @@ -152,29 +157,29 @@ begin WriteInteger('Foobot', 'CurrentFoobot', TheCurrentFoobot); WriteString('Foobot', 'CurrentFoobotName', sFoobotName); WriteFloat(sFoobotName, 'pmTriggerHigh', - double(FooBotTriggerArray[Ord(at_high), C_PM])); + double(FooBotTriggerArray[0, C_PM])); WriteFloat(sFoobotName, 'pmTriggerLow', - double(FooBotTriggerArray[Ord(at_Low), C_PM])); + double(FooBotTriggerArray[1, C_PM])); WriteFloat(sFoobotName, 'tmpTriggerHigh', - double(FooBotTriggerArray[Ord(at_high), C_TMP])); + double(FooBotTriggerArray[0, C_TMP])); WriteFloat(sFoobotName, 'tmpTriggerLow', - double(FooBotTriggerArray[Ord(at_Low), C_TMP])); + double(FooBotTriggerArray[1, C_TMP])); WriteFloat(sFoobotName, 'humTriggerHigh', - double(FooBotTriggerArray[Ord(at_high), C_HUM])); + double(FooBotTriggerArray[0, C_HUM])); WriteFloat(sFoobotName, 'humTriggerLow', - double(FooBotTriggerArray[Ord(at_Low), C_HUM])); + double(FooBotTriggerArray[1, C_HUM])); WriteFloat(sFoobotName, 'co2TriggerHigh', - double(FooBotTriggerArray[Ord(at_high), C_CO2])); + double(FooBotTriggerArray[0, C_CO2])); WriteFloat(sFoobotName, 'co2TriggerLow', - double(FooBotTriggerArray[Ord(at_Low), C_CO2])); + double(FooBotTriggerArray[1, C_CO2])); WriteFloat(sFoobotName, 'vocTriggerHigh', - double(FooBotTriggerArray[Ord(at_high), C_VOC])); + double(FooBotTriggerArray[0, C_VOC])); WriteFloat(sFoobotName, 'vocTriggerLow', - double(FooBotTriggerArray[Ord(at_Low), C_VOC])); + double(FooBotTriggerArray[1, C_VOC])); WriteFloat(sFoobotName, 'allpolluTriggerHigh', - double(FooBotTriggerArray[Ord(at_high), C_ALLPOLLU])); + double(FooBotTriggerArray[0, C_ALLPOLLU])); WriteFloat(sFoobotName, 'allpolluTriggerLow', - double(FooBotTriggerArray[Ord(at_Low), C_ALLPOLLU])); + double(FooBotTriggerArray[1, C_ALLPOLLU])); end; Result := True; except @@ -201,19 +206,19 @@ begin // Load current Foobot triggers with HLINI do begin - FooBotTriggerArray[Ord(at_high), C_PM] := ReadFloat(sFoobotName, 'pmTriggerHigh', 0); - FooBotTriggerArray[Ord(at_low), C_PM] := ReadFloat(sFoobotName, 'pmTriggerLow', 0); - FooBotTriggerArray[Ord(at_high), C_TMP] := ReadFloat(sFoobotName, 'tmpTriggerHigh', 0); - FooBotTriggerArray[Ord(at_low), C_TMP] := ReadFloat(sFoobotName, 'tmpTriggerLow', 0); - FooBotTriggerArray[Ord(at_high), C_HUM] := ReadFloat(sFoobotName, 'humTriggerHigh', 0); - FooBotTriggerArray[Ord(at_low), C_HUM] := ReadFloat(sFoobotName, 'humTriggerLow', 0); - FooBotTriggerArray[Ord(at_high), C_CO2] := ReadFloat(sFoobotName, 'co2TriggerHigh', 0); - FooBotTriggerArray[Ord(at_low), C_CO2] := ReadFloat(sFoobotName, 'co2TriggerLow', 0); - FooBotTriggerArray[Ord(at_high), C_VOC] := ReadFloat(sFoobotName, 'vocTriggerHigh', 0); - FooBotTriggerArray[Ord(at_low), C_VOC] := ReadFloat(sFoobotName, 'vocTriggerLow', 0); - FooBotTriggerArray[Ord(at_high), C_ALLPOLLU] := + FooBotTriggerArray[0, C_PM] := ReadFloat(sFoobotName, 'pmTriggerHigh', 0); + FooBotTriggerArray[1, C_PM] := ReadFloat(sFoobotName, 'pmTriggerLow', 0); + FooBotTriggerArray[0, C_TMP] := ReadFloat(sFoobotName, 'tmpTriggerHigh', 0); + FooBotTriggerArray[1, C_TMP] := ReadFloat(sFoobotName, 'tmpTriggerLow', 0); + FooBotTriggerArray[0, C_HUM] := ReadFloat(sFoobotName, 'humTriggerHigh', 0); + FooBotTriggerArray[1, C_HUM] := ReadFloat(sFoobotName, 'humTriggerLow', 0); + FooBotTriggerArray[0, C_CO2] := ReadFloat(sFoobotName, 'co2TriggerHigh', 0); + FooBotTriggerArray[1, C_CO2] := ReadFloat(sFoobotName, 'co2TriggerLow', 0); + FooBotTriggerArray[0, C_VOC] := ReadFloat(sFoobotName, 'vocTriggerHigh', 0); + FooBotTriggerArray[1, C_VOC] := ReadFloat(sFoobotName, 'vocTriggerLow', 0); + FooBotTriggerArray[0, C_ALLPOLLU] := ReadFloat(sFoobotName, 'allpolluTriggerHigh', 0); - FooBotTriggerArray[Ord(at_low), C_ALLPOLLU] := + FooBotTriggerArray[1, C_ALLPOLLU] := ReadFloat(sFoobotName, 'allpolluTriggerLow', 0); end; Result := True; @@ -365,21 +370,22 @@ var // ========= Internal routines start =========== procedure SetHigh(iMember: integer; aValue: variant; aDateTime: TDateTime); begin + // Do High/Low if aValue > FoobotDataHighs[iMember] then begin FoobotDataHighs[iMember] := aValue; FoobotDataHighTimes[iMember] := aDateTime; SaveHighLows; end; - if ((UseTriggers = True) and (FooBotTriggerArray[1, iMember] <> 0)) then + if ((UseTriggers = True) and (FooBotTriggerArray[0, iMember] <> 0)) then begin - // Process High Trigger + // Do High Trigger // Sets AlertRec record - if (aValue > FooBotTriggerArray[1, iMember]) then + if (aValue > FooBotTriggerArray[0, iMember]) then begin AlertRec[iMember].AlertTriggered := True; AlertRec[iMember].AlertTime := aDateTime; - AlertRec[iMember].AlertType := at_high; + AlertRec[iMember].AlertType := 0; AlertRec[iMember].AlertValue := aValue; end else @@ -389,21 +395,22 @@ var procedure SetLow(iMember: integer; aValue: variant; aDateTime: TDateTime); begin + // Do High/Low if (aValue < FoobotDataLows[iMember]) or (FoobotDataLows[iMember] = 0) then begin FoobotDataLows[iMember] := aValue; FoobotDataLowTimes[iMember] := aDateTime; SaveHighLows; end; - if ((UseTriggers = True) and (FooBotTriggerArray[0, iMember] <> 0)) then + if ((UseTriggers = True) and (FooBotTriggerArray[1, iMember] <> 0)) then begin - // Process Low Trigger + // Do 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].AlertType := 1; AlertRec[iMember].AlertValue := aValue; end else @@ -486,26 +493,46 @@ begin end; +function GetHighTrigger(Const aSensor:Integer):Variant; +//TAlertType = (at_high, at_low) +begin + Result:=0; + if UseTriggers = False then Exit; + If ((aSensor < C_PM) or (aSensor > C_ALLPOLLU)) then exit; + Result:=FooBotTriggerArray[0, aSensor]; +end; + +function GetLowTrigger(Const aSensor:Integer):Variant; +//TAlertType = (at_high, at_low) +begin + Result:=0; + if UseTriggers = False then Exit; + If ((aSensor < C_PM) or (aSensor > C_ALLPOLLU)) then exit; + Result:=FooBotTriggerArray[1, aSensor]; +end; + function SetHighTrigger(const aSensor: integer; const aValue: variant): boolean; +//TAlertType = (at_high, at_low) +begin + Result := False; + if UseTriggers = False then + Exit; + if aValue <> FooBotTriggerArray[0, aSensor] then + begin + FooBotTriggerArray[0, aSensor] := aValue; + Result := True; + end; +end; + +function SetLowTrigger(const aSensor: integer; const aValue: variant): boolean; +//TAlertType = (at_high, at_low) 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: integer; 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; + FooBotTriggerArray[1, aSensor] := aValue; Result := True; end; end; @@ -758,12 +785,12 @@ initialization TheCurrentFoobot := 0; SetLength(FooBotTriggerArray, 2, Succ(C_ALLPOLLU)); SaveLoadHighLows := True; // Default - UseTriggers := False; // Defaul + UseTriggers := False; // Default for giCount := C_PM to C_ALLPOLLU do begin AlertRec[giCount].AlertTriggered := False; AlertRec[giCount].AlertTime := Now; - AlertRec[giCount].AlertType := at_low; + AlertRec[giCount].AlertType := 0; AlertRec[giCount].AlertValue := 0; end; end; diff --git a/applications/foobot/monitor/foobotmonitor.lps b/applications/foobot/monitor/foobotmonitor.lps index cab99b542..c37a912cd 100644 --- a/applications/foobot/monitor/foobotmonitor.lps +++ b/applications/foobot/monitor/foobotmonitor.lps @@ -3,14 +3,14 @@ - + - + @@ -20,8 +20,8 @@ - - + + @@ -34,7 +34,7 @@ - + @@ -44,7 +44,7 @@ - + @@ -53,15 +53,15 @@ - + - - - + + + @@ -71,7 +71,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -101,7 +101,7 @@ - + @@ -110,7 +110,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -189,7 +189,7 @@ - + @@ -218,14 +218,14 @@ - + - + @@ -269,130 +269,130 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - + + - - + + - - + + - - + + - + - - + + diff --git a/applications/foobot/monitor/umainform.pas b/applications/foobot/monitor/umainform.pas index 43662c171..9bb43c3f3 100644 --- a/applications/foobot/monitor/umainform.pas +++ b/applications/foobot/monitor/umainform.pas @@ -199,6 +199,10 @@ type procedure ChangeCurrentFoobot(Sender: TObject); procedure SaveConfig; procedure LoadConfig; + procedure SetMinMaxTriggers; + procedure DoHighTriggerAlert(Const iSensorNum:Integer;Const aValue:Variant); + procedure DoLowTriggerAlert(Const iSensorNum:Integer;Const aValue:Variant); + procedure RestoreNormalColour(Const iSensorNum:Integer); public INI: TCryptINIfile; end; @@ -285,9 +289,6 @@ begin if SaveLoadHighLows then LoadHighLows; GraphHistory; - {$IFNDEF DEBUGMODE} - mnu_optionsTakeReadingNow.Click; - {$ENDIF} // Switch off for testing tmr_foobot.Interval := ONEHOUR; {$IFNDEF DEBUGMODE} @@ -298,7 +299,11 @@ begin PopulateFoobotMenu; LoadTriggers; // This can only be done if we have a Foobot Identity // as each Foobot has its own trigger values + SetMinMaxTriggers; // Adjust if necesarry for Guage High/Low limits Show; + {$IFNDEF DEBUGMODE} + mnu_optionsTakeReadingNow.Click; + {$ENDIF} grp_sensorDisplay.Refresh; grp_highlow.Refresh; Update; @@ -389,31 +394,71 @@ end; procedure Tmainform.SaveConfig; // For all Foobots begin - INI.PlainTextMode := True; - // Colours - INI.WriteString('Config', 'pmColour', ColorToString(as_pm.ColorFore)); - INI.WriteString('Config', 'tmpColour', ColorToString(as_tmp.ColorFore)); - INI.WriteString('Config', 'humColour', ColorToString(as_hum.ColorFore)); - INI.WriteString('Config', 'co2Colour', ColorToString(as_co2.ColorFore)); - INI.WriteString('Config', 'vocColour', ColorToString(as_voc.ColorFore)); - INI.WriteString('Config', 'allpolluColour', ColorToString(as_allpollu.ColorFore)); + With INI do + begin + PlainTextMode := True; + // Colours + WriteString('Config', 'pmColour', ColorToString(as_pm.ColorFore)); + WriteString('Config', 'tmpColour', ColorToString(as_tmp.ColorFore)); + WriteString('Config', 'humColour', ColorToString(as_hum.ColorFore)); + WriteString('Config', 'co2Colour', ColorToString(as_co2.ColorFore)); + WriteString('Config', 'vocColour', ColorToString(as_voc.ColorFore)); + WriteString('Config', 'allpolluColour', ColorToString(as_allpollu.ColorFore)); + // Max and Min + WriteFloat('Config', 'pmMinValue', as_pm.ValueMin); + WriteFloat('Config', 'pmMaxValue', as_pm.ValueMax); + WriteFloat('Config', 'tmpMinValue', as_tmp.ValueMin); + WriteFloat('Config', 'tmpMaxValue', as_tmp.ValueMax); + WriteFloat('Config', 'humMinValue', as_hum.ValueMin); + WriteFloat('Config', 'humMaxValue', as_hum.ValueMax); + WriteFloat('Config', 'co2MinValue', as_co2.ValueMin); + WriteFloat('Config', 'co2MaxValue', as_co2.ValueMax); + WriteFloat('Config', 'vocMinValue', as_voc.ValueMin); + WriteFloat('Config', 'vocMaxValue', as_voc.ValueMax); + WriteFloat('Config', 'allpolluMinValue', as_allpollu.ValueMin); + WriteFloat('Config', 'allpolluMaxValue', as_allpollu.ValueMax); + WriteBool('Config', 'DisplayYellowLines', bDisplayYellowLines); + WriteBool('Config', 'DisplayRedLines', bDisplayRedLines); + // Triggers + WriteBool('Config', 'UseTriggers', UseTriggers); + PlainTextMode := False; + end; +end; - // Max and Min - INI.WriteFloat('Config', 'pmMinValue', as_pm.ValueMin); - INI.WriteFloat('Config', 'pmMaxValue', as_pm.ValueMax); - INI.WriteFloat('Config', 'tmpMinValue', as_tmp.ValueMin); - INI.WriteFloat('Config', 'tmpMaxValue', as_tmp.ValueMax); - INI.WriteFloat('Config', 'humMinValue', as_hum.ValueMin); - INI.WriteFloat('Config', 'humMaxValue', as_hum.ValueMax); - INI.WriteFloat('Config', 'co2MinValue', as_co2.ValueMin); - INI.WriteFloat('Config', 'co2MaxValue', as_co2.ValueMax); - INI.WriteFloat('Config', 'vocMinValue', as_voc.ValueMin); - INI.WriteFloat('Config', 'vocMaxValue', as_voc.ValueMax); - INI.WriteFloat('Config', 'allpolluMinValue', as_allpollu.ValueMin); - INI.WriteFloat('Config', 'allpolluMaxValue', as_allpollu.ValueMax); - INI.WriteBool('Config', 'DisplayYellowLines', bDisplayYellowLines); - INI.WriteBool('Config', 'DisplayRedLines', bDisplayRedLines); - INI.PlainTextMode := False; +procedure Tmainform.SetMinMaxTriggers; +// Ensure Triggers are in range of High & Low guage values +begin + if (UseTriggers = False) then + exit; + if as_pm.ValueMin > GetLowTrigger(C_PM) then + SetLowTrigger(C_PM, as_pm.ValueMin); + if as_pm.ValueMax < GetHighTrigger(C_PM) then + SetHighTrigger(C_PM, as_pm.ValueMax); + + if as_tmp.ValueMin > GetLowTrigger(C_TMP) then + SetLowTrigger(C_TMP, as_tmp.ValueMin); + if as_tmp.ValueMax < GetHighTrigger(C_TMP) then + SetHighTrigger(C_TMP, as_tmp.ValueMax); + + if as_hum.ValueMin > GetLowTrigger(C_HUM) then + SetLowTrigger(C_HUM, as_hum.ValueMin); + if as_hum.ValueMax < GetHighTrigger(C_HUM) then + SetHighTrigger(C_HUM, as_hum.ValueMax); + + if as_co2.ValueMin > GetLowTrigger(C_CO2) then + SetLowTrigger(C_CO2, as_co2.ValueMin); + if as_co2.ValueMax < GetHighTrigger(C_CO2) then + SetHighTrigger(C_CO2, as_co2.ValueMax); + + if as_voc.ValueMin > GetLowTrigger(C_VOC) then + SetLowTrigger(C_VOC, as_voc.ValueMin); + if as_voc.ValueMax < GetHighTrigger(C_VOC) then + SetHighTrigger(C_VOC, as_voc.ValueMax); + + if as_allpollu.ValueMin > GetLowTrigger(C_ALLPOLLU) then + SetLowTrigger(C_ALLPOLLU, as_allpollu.ValueMin); + if as_allpollu.ValueMax < GetHighTrigger(C_ALLPOLLU) then + SetHighTrigger(C_ALLPOLLU, as_allpollu.ValueMax); end; procedure Tmainform.LoadConfig; @@ -447,6 +492,8 @@ begin as_voc.ValueMax := INI.ReadFloat('Config', 'vocMaxValue', MAX_VOC); as_allpollu.ValueMin := INI.ReadFloat('Config', 'allpolluMinValue', MIN_ALLPOLLU); as_allpollu.ValueMax := INI.ReadFloat('Config', 'allpolluMaxValue', MAX_ALLPOLLU); + // Triggers + UseTriggers:=INI.ReadBool('Config', 'UseTriggers', False); INI.PlainTextMode := False; end; @@ -565,7 +612,11 @@ begin not mnu_options_triggersActivateTriggers.Checked; UseTriggers := mnu_options_triggersActivateTriggers.Checked; if UseTriggers then - mnu_options_triggersActivateTriggers.Caption := 'Set Triggers Off' + begin + mnu_options_triggersActivateTriggers.Caption := 'Set Triggers Off'; + LoadTriggers; + SetMinMaxTriggers + end else mnu_options_triggersActivateTriggers.Caption := 'Set Triggers On'; end; @@ -812,7 +863,41 @@ begin SetYellowRecommendedLevels; end; end; +procedure Tmainform.DoHighTriggerAlert(Const iSensorNum:Integer;Const aValue:Variant); +begin + Case iSensorNum of + C_PM:as_pm.Color:=clYellow; + C_TMP:as_tmp.Color:=clYellow; + C_HUM:as_hum.Color:=clYellow; + C_CO2:as_co2.Color:=clYellow; + C_VOC:as_voc.Color:=clYellow; + C_ALLPOLLU:as_allpollu.Color:=clYellow; + end; +end; +procedure Tmainform.DoLowTriggerAlert(Const iSensorNum:Integer;Const aValue:Variant); +begin + Case iSensorNum of + C_PM:as_pm.Color:=clAqua; + C_TMP:as_tmp.Color:=clAqua; + C_HUM:as_hum.Color:=clAqua; + C_CO2:as_co2.Color:=clAqua; + C_VOC:as_voc.Color:=clAqua; + C_ALLPOLLU:as_allpollu.Color:=clAqua; + end; +end; + +procedure Tmainform.RestoreNormalColour(Const iSensorNum:Integer); +begin + Case iSensorNum of + C_PM:as_pm.Color:=clDefault; + C_TMP:as_tmp.Color:=clDefault; + C_HUM:as_hum.Color:=clDefault; + C_CO2:as_co2.Color:=clDefault; + C_VOC:as_voc.Color:=clDefault; + C_ALLPOLLU:as_allpollu.Color:=clDefault; + end; +end; procedure Tmainform.DisplayReadings; var iCount: integer; @@ -841,19 +926,28 @@ begin // Look for alerts in each sensor for iCount := C_PM to C_ALLPOLLU do if AlertRec[iCount].AlertTriggered then + begin // Alert found. High or low? - if AlertRec[iCount].AlertType = at_high then + if AlertRec[iCount].AlertType = 0 then begin // A high alert - do something + DoHighTriggerAlert(iCount,AlertRec[iCount].AlertValue); + { ShowMessageFmt('High alert member %d (value %f) exceeded', [iCount, double(AlertRec[iCount].AlertValue)]); + } end else begin // A low alert - do something + DoLowTriggerAlert(iCount,AlertRec[iCount].AlertValue); + { ShowMessageFmt('Low alert member %d (value %f) exceeded', [iCount, double(AlertRec[iCount].AlertValue)]); + } end; + end + else RestoreNormalColour(iCount); except raise Exception.Create('Unable to process triggers in DisplayReadings'); end;