diff --git a/applications/foobot/monitor/foobot_sensors.pas b/applications/foobot/monitor/foobot_sensors.pas
new file mode 100644
index 000000000..6fd52e905
--- /dev/null
+++ b/applications/foobot/monitor/foobot_sensors.pas
@@ -0,0 +1,487 @@
+{ Copyright (C) 1998-2000, written by Shkolnik Mike
+ FIDOnet: 2:463/106.14
+ E-Mail: mshkolnik@scalabium.com
+ mshkolnik@yahoo.com
+ WEB: http://www.scalabium.com
+ http://www.geocities.com/mshkolnik
+ tel: 380-/44/-552-10-29
+
+ TStopLightSensor and TAnalogSensor sensor components
+ Modified by Jurassic Pork for Lazarus "Industrial" package
+}
+unit foobot_sensors;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses LCLIntf, LCLType, LResources, Classes, Controls, Graphics, Stdctrls, Extctrls;
+
+type
+ TStopLights = (slUNKNOWN, slRED, slYELLOW, slGREEN);
+
+type
+ TSensorPanel = class(TPanel)
+ private
+ FlblShowText: TLabel; {sensor value}
+ FShowText: Boolean;
+ FShowLevel: Boolean; {show the RED and YELLOW levels or not}
+
+ FValue: Double;
+ FValueMin: Double;
+ FValueMax: Double;
+ FValueRed: Double;
+ FValueYellow: Double;
+
+ FColorBack: TColor;
+ FColorFore: TColor;
+ FColorRed: TColor;
+ FColorYellow: TColor;
+
+ function GetCaption: TCaption;
+ procedure SetCaption(AValue: TCaption);
+
+ procedure SetShowText(AValue: Boolean);
+ procedure SetShowLevel(AValue: Boolean);
+
+ procedure SetColorInd(Index: Integer; AValue: TColor);
+
+ procedure SetValue(AValue: Double); virtual;
+ procedure SetValueMin(AValue: Double);
+ procedure SetValueMax(AValue: Double);
+ procedure SetValueRed(AValue: Double);
+ procedure SetValueYellow(AValue: Double);
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ function GetStatus: TStopLights;
+ procedure SetColorState(slStopLight: TStopLights); virtual;
+ published
+ property Caption read GetCaption write SetCaption;
+
+ property ShowText: Boolean read FShowText write SetShowText;
+ property ShowLevel: Boolean read FShowLevel write SetShowLevel;
+
+ property ColorFore: TColor index 0 read FColorFore write SetColorInd default clLime;
+ property ColorBack: TColor index 1 read FColorBack write SetColorInd default clBlack;
+ property ColorRed: TColor index 2 read FColorRed write SetColorInd default clRed;
+ property ColorYellow: TColor index 3 read FColorYellow write SetColorInd default clYellow;
+
+ property Value: Double read FValue write SetValue;
+ property ValueMin: Double read FValueMin write SetValueMin;
+ property ValueMax: Double read FValueMax write SetValueMax;
+ property ValueRed: Double read FValueRed write SetValueRed;
+ property ValueYellow: Double read FValueYellow write SetValueYellow;
+ end;
+
+ TAnalogKind = (akAnalog, akHorizontal, akVertical);
+ TAnalogSensor = class(TSensorPanel)
+ private
+ FAnalogKind: TAnalogKind;
+
+ procedure PaintAsNeedle;
+ procedure PaintAsHorizontal;
+ procedure PaintAsVertical;
+ procedure SetAnalogKind(AValue: TAnalogKind);
+ protected
+ procedure Paint; override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ published
+ property Font;
+ property AnalogKind: TAnalogKind read FAnalogKind write SetAnalogKind;
+ end;
+
+ TStopLightSensor = class(TImage)
+ private
+ FState: TStopLights;
+ procedure SetState(AValue: TStopLights);
+ protected
+ public
+ constructor Create(AOwner: TComponent); override;
+ published
+ property Center default True;
+ property State: TStopLights read FState write SetState;
+ end;
+
+
+implementation
+
+{$R sensors.res}
+
+uses SysUtils;
+
+{ TSensorPanel }
+
+constructor TSensorPanel.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+
+ Height := 75;
+ Width := 170;
+ Parent := AOwner as TWinControl;
+
+ FValue := 0;
+
+ FValueMin := 0;
+ FValueMax := 100;
+ FValueRed := 30;
+ FValueYellow := 60;
+
+ FColorFore := {clGreen} clLime;
+ FColorBack := clBlack {clWhite};
+ FColorRed := clRed;
+ FColorYellow := clYellow;
+
+ FlblShowText := TLabel.Create(Self);
+ with FlblShowText do
+ begin
+ Alignment := taCenter;
+ AutoSize := False;
+ Font := Self.Font;
+ Height := 17;
+ Left := 5;
+ Top := 57;
+ Width := 160;
+ Parent := Self;
+ Align := alBottom;
+ end;
+
+ FShowLevel := True;
+ Caption := '';
+ ShowText := True;
+end;
+
+destructor TSensorPanel.Destroy;
+begin
+// FlblShowText.Free;
+
+ inherited Destroy;
+end;
+
+function TSensorPanel.GetStatus: TStopLights;
+begin
+ Result := slUNKNOWN;
+ if (Value > ValueMin) and (Value < ValueMin) then Result := slGREEN;
+ if (Value < ValueYellow) then Result := slYellow;
+ if (Value < ValueRed) then Result := slRED;
+end;
+
+procedure TSensorPanel.SetColorState(slStopLight: TStopLights);
+begin
+ FlblShowText.Font := Font;
+ case slStopLight of
+ slRED: FlblShowText.Font.Color := FColorRed;
+ slYELLOW: FlblShowText.Font.Color := FColorYellow;
+ else // slUNKNOWN, slGREEN
+// FlblShowText.Font := Font;
+ end;
+end;
+
+procedure TSensorPanel.SetValue(AValue: Double);
+begin
+ if (AValue < FValueMin) then
+ AValue := FValueMin
+ else
+ if (AValue > FValueMax) then
+ AValue := FValueMax;
+ if (FValue <> AValue) then
+ begin
+ FValue := AValue;
+ FlblShowText.Caption := FlblShowText.Hint + FloatToStr(FValue);
+ Invalidate;
+ end;
+end;
+
+function TSensorPanel.GetCaption: TCaption;
+begin
+ // Modif J.P 05/2013 Caption replace Hint
+ Result := FlblShowText.Hint;
+end;
+
+procedure TSensorPanel.SetCaption(AValue: TCaption);
+begin
+ // Modif J.P 05/2013 Caption replace Hint
+ FlblShowText.Hint := AValue;
+ inherited Caption := '';
+ FlblShowText.Caption := FlblShowText.Hint + FloatToStr(FValue);
+ Invalidate;
+end;
+
+procedure TSensorPanel.SetShowText(AValue: Boolean);
+begin
+ if (AValue <> FShowText) then
+ begin
+ FShowText := AValue;
+ FlblShowText.Visible := FShowText;
+ end;
+end;
+
+procedure TSensorPanel.SetShowLevel(AValue: Boolean);
+begin
+ if (AValue <> FShowLevel) then
+ begin
+ FShowlevel := AValue;
+ Invalidate;
+ end;
+end;
+
+procedure TSensorPanel.SetColorInd(Index: Integer; AValue: TColor);
+begin
+ if (AValue <> FColorFore) then
+ begin
+ case Index of
+ 0: FColorFore := AValue;
+ 1: FColorBack := AValue;
+ 2: FColorRed := AValue;
+ 3: FColorYellow := AValue;
+ end;
+ Invalidate;
+ end;
+end;
+
+procedure TSensorPanel.SetValueMin(AValue: Double);
+begin
+ if (AValue <> FValueMin) then
+ begin
+ {
+ if (AValue > FValueMin) then
+ if not (csLoading in ComponentState) then
+ raise EInvalidOperation.CreateFmt('OutOfRange', [-MaxInt, Round(FValueMax - 1)]);
+ }
+ FValueMin := AValue;
+ if (FValue < AValue) then FValue := AValue;
+ Invalidate;
+ end;
+end;
+
+procedure TSensorPanel.SetValueMax(AValue: Double);
+begin
+ if (AValue <> FValueMax) then
+ begin
+ if (AValue < FValueMin) then
+ if not (csLoading in ComponentState) then
+ raise EInvalidOperation.CreateFmt('SOutOfRange', [Round(FValueMin + 1), MaxInt]);
+ FValueMax := AValue;
+ if (FValue > AValue) then FValue := AValue;
+ Invalidate;
+ end;
+end;
+
+procedure TSensorPanel.SetValueRed(AValue: Double);
+begin
+ if (AValue <> FValueRed) then
+ begin
+ if (AValue < FValueMin) or (AValue > FValueMax) then
+ if not (csLoading in ComponentState) then
+ raise EInvalidOperation.CreateFmt('SOutOfRange', [Round(FValueMin), Round(FValueMax)]);
+ FValueRed := AValue;
+ Invalidate;
+ end;
+end;
+
+procedure TSensorPanel.SetValueYellow(AValue: Double);
+begin
+ if (AValue <> FValueYellow) then
+ begin
+ if (AValue < 1) or (AValue > FValueMax) then
+ if not (csLoading in ComponentState) then
+ raise EInvalidOperation.CreateFmt('SOutOfRange', [Round(FValueRed), Round(FValueMax)]);
+ FValueYellow := AValue;
+ Invalidate;
+ end;
+end;
+
+
+{ TAnalogSensor }
+constructor TAnalogSensor.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ Value := 20;
+ AnalogKind := akAnalog;
+end;
+
+procedure TAnalogSensor.Paint;
+begin
+ inherited Paint;
+ case FAnalogKind of
+ akAnalog: PaintAsNeedle;
+ akHorizontal: PaintAsHorizontal;
+ akVertical: PaintAsVertical;
+ end;
+end;
+
+function SolveForY(X, Z: Double): Double;
+begin
+ if Z = 0 then
+ Result := 0
+ else
+ Result := X/Z;
+end;
+
+procedure TAnalogSensor.PaintAsNeedle;
+var MiddleX: Integer;
+ Angle: Double;
+ X, Y, W, H: Integer;
+begin
+ X := 20;
+ Y := 23;
+ W := ClientWidth - 2*20; //130;
+ H := ClientHeight - 2*23; //33;
+ if (W < 1) or (H < 1) then Exit;
+
+ with Canvas do
+ begin
+ Brush.Color := ColorBack;
+ Pen.Color := clBlack;
+ Pen.Width := 1;
+
+ { draw a pie }
+ Pie(X, Y, X + W, Y + 2*H, X + W, Y + H - 1, X, Y + H - 1);
+// Chord(X, Y, X+W, (Y+H)*2, X+W, Y+H-1, X, Y+H-1);
+
+ MiddleX := W div 2;
+ { draw pie for current value }
+ Brush.Color := ColorFore;
+ Pen.Color := clBlack;
+ MoveTo(X + MiddleX, Y + H - 1);
+ Angle := Pi * SolveForY(FValue - FValueMin, FValueMax - FValueMin);
+ Pie(X, Y, X + W, Y + 2*H, Round(X + MiddleX*(1 - Cos(Angle))), Round(Y - 1 + H*(1 - Sin(Angle))), X, Y+H);
+
+ if FShowLevel then
+ begin
+// Pen.Width := 1;
+ { draw a RED level line }
+ Pen.Color := ColorRed;
+ MoveTo(X + MiddleX, Y + H - 1);
+ Angle := Pi * SolveForY(FValueRed - FValueMin, FValueMax - FValueMin);
+ LineTo(Round(X + MiddleX*(1 - Cos(Angle))), Round(Y - 1 + H*(1 - Sin(Angle))));
+
+ { draw a YELLOW level line }
+ Pen.Color := ColorYellow;
+ MoveTo(X + MiddleX, Y + H - 1);
+ Angle := Pi * SolveForY(FValueYellow - FValueMin, FValueMax - FValueMin);
+ LineTo(Round(X + MiddleX*(1 - Cos(Angle))), Round(Y - 1 + H*(1 - Sin(Angle))));
+ end;
+ end;
+end;
+
+procedure TAnalogSensor.PaintAsHorizontal;
+var MiddleX: Integer;
+ X, Y, W, H: Integer;
+begin
+ X := 20;
+ Y := 23;
+ W := ClientWidth - 2*20; //130;
+ H := ClientHeight - 2*23; //33;
+ if (W < 1) or (H < 1) then Exit;
+
+ with Canvas do
+ begin
+ Brush.Color := ColorBack;
+ Pen.Color := clBlack;
+ Pen.Width := 1;
+
+ Rectangle(X, Y, X + W, Y + H);
+
+ { draw pie for current value }
+ Brush.Color := ColorFore;
+ Pen.Color := clBlack;
+ MiddleX := Round(W*SolveForY(FValue - FValueMin, FValueMax - FValueMin));
+ Rectangle(X, Y, X + MiddleX, Y + H);
+
+ if FShowLevel then
+ begin
+ { draw a RED level line }
+ Pen.Color := ColorRed;
+ MiddleX := Round(W*SolveForY(FValueRed - FValueMin, FValueMax - FValueMin));
+ MoveTo(X + MiddleX, Y + 1);
+ LineTo(X + MiddleX, Y + H - 1);
+
+ { draw a YELLOW level line }
+ Pen.Color := ColorYellow;
+ MiddleX := Round(W*SolveForY(FValueYellow - FValueMin, FValueMax - FValueMin));
+ MoveTo(X + MiddleX, Y + 1);
+ LineTo(X + MiddleX, Y + H - 1);
+ end;
+ end;
+end;
+
+procedure TAnalogSensor.PaintAsVertical;
+var MiddleY: Integer;
+ X, Y, W, H: Integer;
+begin
+ X := 20;
+ Y := 23;
+ W := ClientWidth - 2*20; //130;
+ H := ClientHeight - 2*23; //33;
+ if (W < 1) or (H < 1) then Exit;
+
+ with Canvas do
+ begin
+ Brush.Color := ColorBack;
+ Pen.Color := clBlack;
+ Pen.Width := 1;
+
+ Rectangle(X + W - 1, Y + H - 1, X, Y);
+
+ { draw pie for current value }
+ Brush.Color := ColorFore;
+ Pen.Color := clBlack;
+ MiddleY := Round(H*SolveForY(FValue - FValueMin, FValueMax - FValueMin));
+ Rectangle(X, Y + H - 1 - MiddleY, X + W - 1, Y + H - 1);
+
+ if FShowLevel then
+ begin
+ { draw a RED level line }
+ Pen.Color := ColorRed;
+ MiddleY := Round(H*SolveForY(FValueRed - FValueMin, FValueMax - FValueMin));
+ MoveTo(X + 1, Y + H - 1 - MiddleY);
+ LineTo(X + W - 1, Y + H - 1 - MiddleY);
+
+ { draw a YELLOW level line }
+ Pen.Color := ColorYellow;
+ MiddleY := Round(H*SolveForY(FValueYellow - FValueMin, FValueMax - FValueMin));
+ MoveTo(X + 1, Y + H - 1 - MiddleY);
+ LineTo(X + W - 1, Y + H - 1 - MiddleY);
+ end;
+ end;
+end;
+
+procedure TAnalogSensor.SetAnalogKind(AValue: TAnalogKind);
+begin
+ if (AValue <> FAnalogKind) then
+ begin
+ FAnalogKind := AValue;
+ Invalidate;
+ end;
+end;
+
+{ TStopLightSensor }
+constructor TStopLightSensor.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+
+ Width := 23;
+ Height := 43;
+ Center := True;
+ FState := slRED;
+ State := slUNKNOWN;
+end;
+
+procedure TStopLightSensor.SetState(AValue: TStopLights);
+begin
+ if (AValue <> FState) then
+ begin
+ FState := AValue;
+
+ case AValue of
+ slUNKNOWN: Picture.LoadFromResourceName(HInstance, 'STOP_UNKNOWN', TPortableNetworkGraphic);
+ slRED: Picture.LoadFromResourceName(HInstance, 'STOP_RED', TPortableNetworkGraphic);
+ slYELLOW: Picture.LoadFromResourceName(HInstance, 'STOP_YELLOW', TPortableNetworkGraphic);
+ slGREEN: Picture.LoadFromResourceName(HInstance, 'STOP_GREEN', TPortableNetworkGraphic);
+ end;
+ end;
+end;
+
+end.
diff --git a/applications/foobot/monitor/foobotmonitor.lps b/applications/foobot/monitor/foobotmonitor.lps
index aa9bfb52d..4878bd169 100644
--- a/applications/foobot/monitor/foobotmonitor.lps
+++ b/applications/foobot/monitor/foobotmonitor.lps
@@ -4,13 +4,13 @@
-
+
-
+
-
+
@@ -19,10 +19,9 @@
-
-
-
-
+
+
+
@@ -32,9 +31,9 @@
-
+
-
+
@@ -44,7 +43,7 @@
-
+
@@ -53,15 +52,15 @@
-
+
-
+
-
+
@@ -71,21 +70,21 @@
-
+
-
+
-
+
-
+
-
+
@@ -118,10 +117,10 @@
-
+
-
+
@@ -152,12 +151,13 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -190,19 +190,34 @@
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -210,123 +225,123 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
diff --git a/applications/foobot/monitor/innosetup/setup_foobotmonitor.exe b/applications/foobot/monitor/innosetup/setup_foobotmonitor.exe
index 1dc168549..5b8f3f6f2 100644
Binary files a/applications/foobot/monitor/innosetup/setup_foobotmonitor.exe and b/applications/foobot/monitor/innosetup/setup_foobotmonitor.exe differ
diff --git a/applications/foobot/monitor/linuxbinaries/foobotmonitor.zip b/applications/foobot/monitor/linuxbinaries/foobotmonitor.zip
index 9ee772c4e..78fce2f2b 100644
Binary files a/applications/foobot/monitor/linuxbinaries/foobotmonitor.zip and b/applications/foobot/monitor/linuxbinaries/foobotmonitor.zip differ
diff --git a/applications/foobot/monitor/umainform.lfm b/applications/foobot/monitor/umainform.lfm
index a9fe255f8..0ceb0c1f1 100644
--- a/applications/foobot/monitor/umainform.lfm
+++ b/applications/foobot/monitor/umainform.lfm
@@ -415,6 +415,11 @@ object mainform: Tmainform
end
object mnu_optionsSampleEvery: TMenuItem
Caption = 'Sample every...'
+ object mnu_SampleEveryHalfHour: TMenuItem
+ AutoCheck = True
+ Caption = 'Half-Hour'
+ OnClick = mnu_SampleEveryHalfHourClick
+ end
object mnu_SampleEvery1Hour: TMenuItem
AutoCheck = True
Caption = 'Hour (default)'
diff --git a/applications/foobot/monitor/umainform.pas b/applications/foobot/monitor/umainform.pas
index 1687be63e..ee5d946c5 100644
--- a/applications/foobot/monitor/umainform.pas
+++ b/applications/foobot/monitor/umainform.pas
@@ -25,10 +25,12 @@ V0.0.1.0: Initial commit
V0.0.2.0: Trayicon added
V0.0.3.0: Added Help menu. Updated Options menu
V0.0.4.0: Graph added
-V0.0.5.0: ??
+V0.1.0.0: Save/Load Alltime High/Lows. Reset values from menu
+V0.1.1.0: Save/Load Colours, Min and Max values to cfg file
+V0.1.2.0: ??
}
{$ifopt D+}
-// Debug mode
+// Debug mode does not load data from web
{$ENDIF}
{$mode objfpc}{$H+}
@@ -36,13 +38,14 @@ V0.0.5.0: ??
interface
uses
- Classes, SysUtils, FileUtil, TAGraph, TAIntervalSources, TASeries,
+ SysUtils, TAGraph, TAIntervalSources, TASeries,
Sensors, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, Menus,
- lclIntf, foobot_utility, uCryptIni, Variants, dateutils, uconfigform;
+ lclIntf, foobot_utility, uCryptIni, dateutils, uconfigform, Classes;
const
// Timer milliseconds
ONEMINUTE = 60000;
+ HALFHOUR = ONEMINUTE * 30;
ONEHOUR = ONEMINUTE * 60;
TWOHOURS = ONEHOUR * 2;
FOURHOURS = ONEHOUR * 4;
@@ -71,6 +74,13 @@ const
MIN_ALLPOLLU = 0;
MAX_ALLPOLLU = 700;
+ // Sensor recommended levels
+ REC_PM = 25;
+ REC_TMP = 23;
+ REC_HUM = 60;
+ REC_CO2 = 1300;
+ REC_VOC = 300;
+ REC_ALLPOLLU = 50;
type
@@ -113,6 +123,7 @@ type
lbl_voclow: TLabel;
lbl_allpollulow: TLabel;
MainMenu1: TMainMenu;
+ mnu_SampleEveryHalfHour: TMenuItem;
mnu_optionsResetHighsLows: TMenuItem;
mnu_optionsOnlineHelp: TMenuItem;
mnu_optionsSeperator1: TMenuItem;
@@ -155,6 +166,7 @@ type
procedure mnu_SampleEvery2HoursClick(Sender: TObject);
procedure mnu_SampleEvery4HoursClick(Sender: TObject);
procedure mnu_SampleEvery8HoursClick(Sender: TObject);
+ procedure mnu_SampleEveryHalfHourClick(Sender: TObject);
procedure tmr_foobotTimer(Sender: TObject);
procedure TrayIcon1Click(Sender: TObject);
private
@@ -166,6 +178,7 @@ type
procedure UpdateHighLow(SensorNumber: integer);
procedure GraphHistory;
procedure GraphCurrentReading;
+ Procedure SetRecommendedLevels;
procedure SaveConfig;
procedure LoadConfig;
public
@@ -243,12 +256,12 @@ begin
GraphHistory;
{$IFNDEF DEBUGMODE}
mnu_optionsTakeReadingNow.Click;
-{$ENDIF}
+ {$ENDIF}
// Switch off for testing
tmr_foobot.Interval := ONEHOUR;
{$IFNDEF DEBUGMODE}
tmr_foobot.Enabled := True;
-{$ENDIF}
+ {$ENDIF}
Show;
end;
end
@@ -436,6 +449,12 @@ begin
ShowMessage('Sorry - no readings available');
mainform.Cursor := crDefault;
end;
+procedure Tmainform.mnu_SampleEveryHalfHourClick(Sender: TObject);
+begin
+ tmr_foobot.Enabled := False;
+ tmr_foobot.Interval := HALFHOUR;
+ tmr_foobot.Enabled := True;
+end;
procedure Tmainform.mnu_SampleEvery1HourClick(Sender: TObject);
begin
@@ -472,6 +491,7 @@ begin
tmr_foobot.Enabled := True;
end;
+
procedure Tmainform.tmr_foobotTimer(Sender: TObject);
begin
if FetchFoobotData(dfLast, 0, 0, 0, 0, 0, sSecretKey) then
@@ -483,6 +503,16 @@ begin
mainform.Show;
end;
+Procedure Tmainform.SetRecommendedLevels;
+begin
+ as_pm.ValueYellow:=REC_PM;
+ as_tmp.ValueYellow:=REC_TMP;
+ as_hum.ValueYellow:=REC_HUM;
+ as_co2.ValueYellow:=REC_CO2;
+ as_voc.ValueYellow:=REC_VOC;
+ as_allpollu.ValueYellow:=REC_ALLPOLLU;
+end;
+
procedure Tmainform.UpdateHighLow(SensorNumber: integer);
begin
case SensorNumber of
@@ -596,6 +626,7 @@ begin
ValueYellow := ValueMax;
if Value > ValueRed then
ValueRed := Value;
+ SetRecommendedLevels;
end;
end;