V0.1 Initial Commit

Pascal source to access Foobot data

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5569 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
gbamber
2016-12-29 13:18:01 +00:00
parent 4ace082188
commit 6c7b2b14ed
24 changed files with 6011 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -0,0 +1,338 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="10"/>
<PathDelim Value="\"/>
<General>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="Foobot Interrogator"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<XPManifest>
<TextName Value="CompanyName.ProductName.AppName"/>
<TextDesc Value="Your application description."/>
</XPManifest>
<Icon Value="0"/>
</General>
<VersionInfo>
<UseVersionInfo Value="True"/>
<MinorVersionNr Value="1"/>
<StringTable Comments="Uses foobot public API" LegalCopyright="(c)2016 minesadorada@charcodelvalle.com" ProductName="fpc/Lazarus" ProductVersion="3.1.1.0"/>
</VersionInfo>
<BuildModes Count="6">
<Item1 Name="Win32" Default="True"/>
<Item2 Name="Win64">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\win64\foobotinterrogator"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<TargetCPU Value="x86_64"/>
<TargetOS Value="win64"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CustomOptions Value="-FcUTF8"/>
<OtherDefines Count="1">
<Define0 Value="DEBUG"/>
</OtherDefines>
</Other>
</CompilerOptions>
</Item2>
<Item3 Name="Linux32">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\linux32\foobotinterrogator"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<TargetCPU Value="i386"/>
<TargetOS Value="linux"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CustomOptions Value="-FcUTF8"/>
</Other>
</CompilerOptions>
</Item3>
<Item4 Name="Linux64">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\linux64\foobotinterrogator"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<TargetCPU Value="x86_64"/>
<TargetOS Value="linux"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CustomOptions Value="-FcUTF8"/>
</Other>
</CompilerOptions>
</Item4>
<Item5 Name="Win32Debug">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\win32debug\foobotinterrogator"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<Checks>
<IOChecks Value="True"/>
<RangeChecks Value="True"/>
<OverflowChecks Value="True"/>
<StackChecks Value="True"/>
</Checks>
<VerifyObjMethodCallValidity Value="True"/>
<TargetCPU Value="i386"/>
<TargetOS Value="win32"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<UseHeaptrc Value="True"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CustomOptions Value="-dDEBUG
-FcUTF8"/>
<OtherDefines Count="1">
<Define0 Value="DEBUG"/>
</OtherDefines>
</Other>
</CompilerOptions>
</Item5>
<Item6 Name="Win32GTK">
<MacroValues Count="1">
<Macro1 Name="LCLWidgetType" Value="gtk2"/>
</MacroValues>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\win32GTK\foobotinterrogator"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<TargetCPU Value="i386"/>
<TargetOS Value="win32"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CustomOptions Value="-FcUTF8"/>
<OtherDefines Count="1">
<Define0 Value="DEBUG"/>
</OtherDefines>
</Other>
</CompilerOptions>
</Item6>
<SharedMatrixOptions Count="1">
<Item1 ID="766380513179" Modes="Win32GTK" Type="IDEMacro" MacroName="LCLWidgetType" Value="gtk2"/>
</SharedMatrixOptions>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="2">
<Item1>
<PackageName Value="cryptini"/>
<MinVersion Minor="1" Release="2" Valid="True"/>
</Item1>
<Item2>
<PackageName Value="LCL"/>
</Item2>
</RequiredPackages>
<Units Count="7">
<Unit0>
<Filename Value="foobot.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="umainform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="mainform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit1>
<Unit2>
<Filename Value="foobot_objects.pas"/>
<IsPartOfProject Value="True"/>
</Unit2>
<Unit3>
<Filename Value="foobot_httpclient.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="ulogin.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="loginform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit4>
<Unit5>
<Filename Value="udataform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="dataform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit5>
<Unit6>
<Filename Value="foobot_utility.pas"/>
<IsPartOfProject Value="True"/>
</Unit6>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\win32\foobotinterrogator"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<SmartLinkUnit Value="True"/>
<TargetCPU Value="i386"/>
<TargetOS Value="win32"/>
<Optimizations>
<OptimizationLevel Value="3"/>
</Optimizations>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<LinkSmart Value="True"/>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CustomOptions Value="-FcUTF8"/>
<OtherDefines Count="1">
<Define0 Value="DEBUG"/>
</OtherDefines>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="4">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
<Item4>
<Name Value="EHTTPClient"/>
</Item4>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,53 @@
program foobot;
{ Foobot Interrogator
Copyright (C)2016 Gordon Bamber minsadorada@charcodelvalle.com
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
{$ifdef Linux}
{$ifdef FPC_CROSSCOMPILING}
{$ifdef CPUARM}
//if GUI, then uncomment
//{$linklib GLESv2}
{$endif}
{$linklib libc_nonshared.a}
{$endif}
{$endif}
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, umainform, foobot_objects, foobot_httpclient, ulogin, udataform,
foobot_utility
{ you can add units after this };
{$R *.res}
begin
Application.Title:='Foobot Interrogator';
RequireDerivedFormResource:=True;
Application.Initialize;
Application.CreateForm(Tmainform, mainform);
Application.CreateForm(Tloginform, loginform);
Application.CreateForm(Tdataform, dataform);
Application.Run;
end.

View File

@ -0,0 +1,339 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectSession>
<PathDelim Value="\"/>
<Version Value="10"/>
<BuildModes Active="Win64"/>
<Units Count="25">
<Unit0>
<Filename Value="foobot.lpr"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="7"/>
<TopLine Value="6"/>
<CursorPos Y="44"/>
<UsageCount Value="93"/>
<Loaded Value="True"/>
</Unit0>
<Unit1>
<Filename Value="umainform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="mainform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<IsVisibleTab Value="True"/>
<TopLine Value="174"/>
<CursorPos X="31" Y="257"/>
<UsageCount Value="93"/>
<Loaded Value="True"/>
<LoadedDesigner Value="True"/>
</Unit1>
<Unit2>
<Filename Value="foobot_objects.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="2"/>
<TopLine Value="80"/>
<CursorPos Y="101"/>
<UsageCount Value="53"/>
<Loaded Value="True"/>
</Unit2>
<Unit3>
<Filename Value="foobot_httpclient.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="5"/>
<TopLine Value="348"/>
<CursorPos X="17" Y="369"/>
<UsageCount Value="55"/>
<Loaded Value="True"/>
</Unit3>
<Unit4>
<Filename Value="ulogin.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="loginform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<EditorIndex Value="6"/>
<CursorPos Y="92"/>
<UsageCount Value="47"/>
<Loaded Value="True"/>
<LoadedDesigner Value="True"/>
</Unit4>
<Unit5>
<Filename Value="udataform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="dataform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<EditorIndex Value="3"/>
<TopLine Value="8"/>
<CursorPos X="30" Y="51"/>
<UsageCount Value="46"/>
<Loaded Value="True"/>
<LoadedDesigner Value="True"/>
</Unit5>
<Unit6>
<Filename Value="foobot_utility.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="1"/>
<TopLine Value="27"/>
<CursorPos X="50" Y="52"/>
<UsageCount Value="24"/>
<Loaded Value="True"/>
</Unit6>
<Unit7>
<Filename Value="..\..\components\cryptini\latest_stable\ucryptini.pas"/>
<EditorIndex Value="4"/>
<TopLine Value="262"/>
<CursorPos X="47" Y="232"/>
<UsageCount Value="22"/>
<Loaded Value="True"/>
</Unit7>
<Unit8>
<Filename Value="C:\trunklatest\fpc\rtl\objpas\sysutils\sysutilh.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="85"/>
<CursorPos X="4" Y="107"/>
<UsageCount Value="37"/>
</Unit8>
<Unit9>
<Filename Value="..\json_packager\umain.pas"/>
<ComponentName Value="frmMain"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<EditorIndex Value="-1"/>
<TopLine Value="1358"/>
<CursorPos Y="1369"/>
<UsageCount Value="28"/>
</Unit9>
<Unit10>
<Filename Value="..\..\components\cryptini\latest_stable\demo\umainform.pas"/>
<ComponentName Value="mainform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<EditorIndex Value="-1"/>
<TopLine Value="214"/>
<CursorPos Y="235"/>
<UsageCount Value="6"/>
</Unit10>
<Unit11>
<Filename Value="D:\lazarustrunk\common_components\onlinepackagemanager\onlinepackagemanager\opkman_downloader.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="614"/>
<CursorPos X="60" Y="565"/>
<UsageCount Value="35"/>
</Unit11>
<Unit12>
<Filename Value="D:\lazarustrunk\common_components\onlinepackagemanager\onlinepackagemanager\opkman_updates.pas"/>
<EditorIndex Value="-1"/>
<CursorPos X="67" Y="8"/>
<UsageCount Value="6"/>
</Unit12>
<Unit13>
<Filename Value="C:\trunklatest\fpc\packages\fcl-json\src\fpjson.pp"/>
<EditorIndex Value="-1"/>
<TopLine Value="10"/>
<CursorPos X="12" Y="29"/>
<UsageCount Value="38"/>
</Unit13>
<Unit14>
<Filename Value="C:\trunklatest\fpc\packages\fcl-json\src\fpjsonrtti.pp"/>
<EditorIndex Value="-1"/>
<TopLine Value="131"/>
<CursorPos X="27" Y="138"/>
<UsageCount Value="38"/>
</Unit14>
<Unit15>
<Filename Value="C:\trunklatest\fpc\rtl\objpas\classes\classesh.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="476"/>
<CursorPos X="3" Y="480"/>
<UsageCount Value="28"/>
</Unit15>
<Unit16>
<Filename Value="ugenericcollection.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="6"/>
<CursorPos X="13" Y="32"/>
<UsageCount Value="26"/>
</Unit16>
<Unit17>
<Filename Value="C:\trunklatest\fpc\rtl\objpas\classes\collect.inc"/>
<EditorIndex Value="-1"/>
<CursorPos X="32" Y="96"/>
<UsageCount Value="26"/>
</Unit17>
<Unit18>
<Filename Value="C:\trunklatest\lazarus\lcl\comctrls.pp"/>
<UnitName Value="ComCtrls"/>
<EditorIndex Value="-1"/>
<TopLine Value="3464"/>
<CursorPos X="3" Y="3585"/>
<UsageCount Value="24"/>
</Unit18>
<Unit19>
<Filename Value="C:\trunklatest\lazarus\lcl\include\treeview.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="1581"/>
<CursorPos Y="1603"/>
<UsageCount Value="22"/>
</Unit19>
<Unit20>
<Filename Value="..\..\fpc\examples\fcl-json\parsedemo.pp"/>
<EditorIndex Value="-1"/>
<TopLine Value="28"/>
<UsageCount Value="9"/>
</Unit20>
<Unit21>
<Filename Value="..\..\fpc\examples\fcl-json\simpledemo.pp"/>
<EditorIndex Value="-1"/>
<TopLine Value="278"/>
<CursorPos X="17" Y="311"/>
<UsageCount Value="17"/>
</Unit21>
<Unit22>
<Filename Value="..\..\fpc\packages\fcl-json\examples\demortti.pp"/>
<EditorIndex Value="-1"/>
<UsageCount Value="16"/>
</Unit22>
<Unit23>
<Filename Value="C:\trunklatest\lazarus\lcl\grids.pas"/>
<UnitName Value="Grids"/>
<EditorIndex Value="-1"/>
<TopLine Value="9389"/>
<CursorPos Y="9411"/>
<UsageCount Value="12"/>
</Unit23>
<Unit24>
<Filename Value="C:\trunklatest\fpc\rtl\objpas\sysutils\datih.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="50"/>
<CursorPos X="10" Y="155"/>
<UsageCount Value="12"/>
</Unit24>
</Units>
<OtherDefines Count="1">
<Define0 Value="DEBUG"/>
</OtherDefines>
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="umainform.pas"/>
<Caret Line="290" TopLine="271"/>
</Position1>
<Position2>
<Filename Value="umainform.pas"/>
<Caret Line="281" TopLine="274"/>
</Position2>
<Position3>
<Filename Value="umainform.pas"/>
<Caret Line="282" TopLine="268"/>
</Position3>
<Position4>
<Filename Value="umainform.pas"/>
<Caret Line="36" Column="31" TopLine="16"/>
</Position4>
<Position5>
<Filename Value="umainform.pas"/>
<Caret Line="242" Column="9" TopLine="240"/>
</Position5>
<Position6>
<Filename Value="umainform.pas"/>
<Caret Line="218" Column="11" TopLine="214"/>
</Position6>
<Position7>
<Filename Value="foobot_utility.pas"/>
<Caret Line="8" Column="46" TopLine="4"/>
</Position7>
<Position8>
<Filename Value="umainform.pas"/>
<Caret Line="152" Column="3" TopLine="127"/>
</Position8>
<Position9>
<Filename Value="foobot_utility.pas"/>
<Caret Line="8" Column="36"/>
</Position9>
<Position10>
<Filename Value="foobot_utility.pas"/>
<Caret Line="7" Column="29" TopLine="2"/>
</Position10>
<Position11>
<Filename Value="foobot_utility.pas"/>
<Caret Line="22" Column="99"/>
</Position11>
<Position12>
<Filename Value="foobot_utility.pas"/>
<Caret Line="23" Column="21"/>
</Position12>
<Position13>
<Filename Value="foobot_utility.pas"/>
<Caret Line="74" Column="15" TopLine="72"/>
</Position13>
<Position14>
<Filename Value="foobot_utility.pas"/>
<Caret Line="88" Column="75" TopLine="65"/>
</Position14>
<Position15>
<Filename Value="umainform.pas"/>
<Caret Line="279" TopLine="254"/>
</Position15>
<Position16>
<Filename Value="umainform.pas"/>
<Caret Line="246" Column="42" TopLine="230"/>
</Position16>
<Position17>
<Filename Value="umainform.pas"/>
<Caret Line="245" Column="32" TopLine="223"/>
</Position17>
<Position18>
<Filename Value="umainform.pas"/>
<Caret Line="282" TopLine="275"/>
</Position18>
<Position19>
<Filename Value="foobot_utility.pas"/>
<Caret Line="28" TopLine="10"/>
</Position19>
<Position20>
<Filename Value="umainform.pas"/>
<Caret Line="107" Column="21" TopLine="78"/>
</Position20>
<Position21>
<Filename Value="umainform.pas"/>
<Caret Line="35" Column="47" TopLine="28"/>
</Position21>
<Position22>
<Filename Value="foobot.lpr"/>
<Caret Line="44" TopLine="6"/>
</Position22>
<Position23>
<Filename Value="foobot_objects.pas"/>
<Caret Line="101" TopLine="80"/>
</Position23>
<Position24>
<Filename Value="umainform.pas"/>
<Caret Line="216" Column="26" TopLine="211"/>
</Position24>
<Position25>
<Filename Value="umainform.pas"/>
<Caret Line="90" TopLine="72"/>
</Position25>
<Position26>
<Filename Value="foobot_utility.pas"/>
<Caret Line="40" Column="56" TopLine="18"/>
</Position26>
<Position27>
<Filename Value="foobot_utility.pas"/>
<Caret Line="72" Column="56" TopLine="50"/>
</Position27>
<Position28>
<Filename Value="foobot_utility.pas"/>
<Caret Line="86" Column="45" TopLine="63"/>
</Position28>
<Position29>
<Filename Value="foobot_utility.pas"/>
<Caret Line="50" TopLine="27"/>
</Position29>
<Position30>
<Filename Value="umainform.pas"/>
<Caret Line="85" TopLine="193"/>
</Position30>
</JumpHistory>
</ProjectSession>
</CONFIG>

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,197 @@
unit foobot_objects;
{ Objects for Foobot Interrogator
Copyright (C)2016 Gordon Bamber minsadorada@charcodelvalle.com
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, ugenericcollection, fpjsonrtti;
{TFoobotIdentities}
type
TFoobotIdentities = class(TCollectionItem)
// JSON fields here as properties
private
Fuuid: string;
FuserId: integer;
FMac: string;
FName: string;
public
published
property uuid: string read Fuuid write Fuuid;
property userId: integer read FuserId write FuserId;
property mac: string read FMac write FMac;
property name: string read FName write FName;
end;
{TFoobotIdentityList}
TFoobotIdentityList = specialize TGenericCollection<TFoobotIdentities>;
{TFoobotIdentityObject}
// Contains a list of TFoobotIdentities as a TCollection
type
TFoobotIdentityObject = class(TPersistent)
private
FFoobotIdentityList: TFoobotIdentityList;
public
constructor Create;
destructor Destroy; override;
function SaveToFile(const AFilename: string): boolean;
function LoadFromFile(const AFileName: string): boolean;
published
property FoobotIdentityList: TFoobotIdentityList
read FFoobotIdentityList write FFoobotIdentityList;
end;
type
TFoobotDataObject = class(TPersistent)
private
FDataPoints:Variant;
FSensors:TStrings;
FUnits:TStrings;
Fuuid:String;
FStart:Int64;
FEnd:Int64;
public
constructor Create;
Destructor Destroy; override;
function SaveToFile(const AFilename: string): boolean;
published
property uuid:String read Fuuid write Fuuid;
property start:Int64 read FStart write FStart;
property &end:Int64 read FEnd write FEnd;
property sensors:TStrings
read FSensors write FSensors;
property units:TStrings
read FUnits write FUnits;
property datapoints : Variant read FDataPoints write FDataPoints;
end;
implementation
constructor TFoobotDataObject.Create;
begin
inherited;
FSensors:=TStringList.Create;
FUnits:=TstringList.Create;
end;
Destructor TFoobotDataObject.Destroy;
begin
FSensors.Free;
FUnits.Free;
inherited Destroy;
end;
{TFoobotIdentityObject}
constructor TFoobotIdentityObject.Create;
begin
inherited;
FFoobotIdentityList := TFoobotIdentityList.Create;
end;
destructor TFoobotIdentityObject.Destroy;
var
c: TCollectionItem;
begin
for c in FFoobotIdentityList do
c.Free;
FFoobotIdentityList.Free;
inherited Destroy;
end;
function TFoobotIdentityObject.LoadFromFile(const AFileName: string): boolean;
var
DeStreamer: TJSONDeStreamer;
s: TStringList;
begin
Result := True;
s := TStringList.Create;
try
s.LoadFromFile(AFileName);
DeStreamer := TJSONDeStreamer.Create(nil);
try
DeStreamer.JSONToObject(s.Text, Self);
except
// Eat the exception
On E: Exception do
Result := False;
end;
finally
DeStreamer.Free;
s.Free;
end;
end;
function TFoobotIdentityObject.SaveToFile(const AFilename: string): boolean;
var
Streamer: TJSONStreamer;
s: TStringList;
begin
Result := True;
s := TStringList.Create;
try
Streamer := TJSONStreamer.Create(nil);
Streamer.Options := Streamer.Options + [jsoUseFormatString];
s.AddText(Streamer.ObjectToJSONString(Self));
try
s.SaveToFile(AFileName);
except
// Eat the exception
On E: Exception do
Result := False;
end;
finally
Streamer.Free;
s.Free;
end;
end;
function TFoobotDataObject.SaveToFile(const AFilename: string): boolean;
var
Streamer: TJSONStreamer;
s: TStringList;
begin
Result := True;
s := TStringList.Create;
try
Streamer := TJSONStreamer.Create(nil);
Streamer.Options := Streamer.Options + [jsoUseFormatString];
s.AddText(Streamer.ObjectToJSONString(Self));
try
s.SaveToFile(AFileName);
except
// Eat the exception
On E: Exception do
Result := False;
end;
finally
Streamer.Free;
s.Free;
end;
end;
end.

View File

@ -0,0 +1,533 @@
unit foobot_utility;
{ Foobot Interrogator Utilities
Copyright (C)2016 Gordon Bamber minsadorada@charcodelvalle.com
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
VERSION HISTORY
===============
* HighLow routines
* Use GetAppGonfigFile for IniFile location
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Dialogs,
foobot_httpclient, foobot_objects, fpjson, fpjsonrtti, base64, variants,
DateUtils,INIFiles;
const
FOOBOT_USER_URL = 'https://api.foobot.io/v2/user/%s/login/';
FOOBOT_IDENTITY_URL = 'https://api.foobot.io/v2/owner/%s/device/';
FOOBOT_DATA_LAST_URL = 'https://api.foobot.io/v2/device/%s/datapoint/%s/%s/%s/';
FOOBOT_DATA_START_FINISH_URL =
'https://api.foobot.io/v2/device/%s/datapoint/%s/%s/%s/';
HIGHLOWMAX = 6;
type
TDataFetchType = (dfLast, dfStartEnd);
TSensorType = (st_time,st_pm,st_tmp,st_hum,st_co2,st_voc,st_allpollu);
function EncodeStringBase64(const s: string): string;
function FetchAuthenticationKey(aUsername, aUserPassword: string): boolean;
// Populates FoobotIdentityObject.TFoobotIdentityList collection
function FetchFoobotIdentity(aUsername, aSecretKey: string): boolean;
// Populates FoobotIdentityObject
function FetchFoobotData(DataFetchType: TDataFetchType = dfLast;
iCurrentFoobot: integer = 0; iLastIntervalSeconds: integer = 3600;
iLastAverageBySeconds: integer = 0; iStartTimeSeconds: int64 = 0;
iEndTimeSeconds: int64 = 0; aSecretKey: string = 'unknown'): boolean;
// Populates datapoint arrays from FoobotIdentityObject for easy access
// - also populates HighLow arrays
function FoobotDataObjectToArrays: boolean;
// Utility functions
function ResetArrays: boolean;
function ResetObjects: boolean;
Function ResetHighLows:Boolean;
function SaveHighLows:Boolean;
Function LoadHighLows:Boolean;
var
HttpClient: TFPHTTPClient;
FoobotIdentityObject: TFoobotIdentityObject;
FoobotDataObject: TFoobotDataObject;
sAuthenticationKey: string;
SensorType:TSensorType;
SaveLoadHighLows:Boolean;
TheCurrentFoobot:Integer;
HLINI:TIniFile;
// Easier access to datapoints
// Call FoobotDataObjectToArrays to populate them
FoobotData_time: array of TDateTime;
FoobotData_pm: array of double;
FoobotData_tmp: array of double;
FoobotData_hum: array of double;
FoobotData_co2: array of integer;
FoobotData_voc: array of integer;
FoobotData_allpollu: array of double;
// Set in FoobotDataObjectToArrays
FoobotDataHighs:Array[0..HIGHLOWMAX]of Variant;
FoobotDataLows:Array[0..HIGHLOWMAX]of Variant;
FoobotDataHighTimes:Array[0..HIGHLOWMAX]of Variant;
FoobotDataLowTimes:Array[0..HIGHLOWMAX]of Variant;
implementation
function SaveHighLows:Boolean;
Var sFoobotName:String;
begin
If SaveLoadHighLows=FALSE then Exit(FALSE);
sFoobotName:=FoobotIdentityObject.FoobotIdentityList[TheCurrentFoobot].name;
If Not Assigned(HLINI) then
HLINI:=TIniFile.Create(ChangeFileExt(GetAppConfigFile(False),'.ini'));
// Store current Foobot info
HLINI.WriteInteger('Foobot','CurrentFoobot',TheCurrentFoobot);
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]));
// 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]));
// 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]));
// 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]));
// 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]));
// 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]));
end;
Function LoadHighLows:Boolean;
Var sFoobotName:String;
begin
If SaveLoadHighLows=FALSE then Exit(FALSE);
sFoobotName:=FoobotIdentityObject.FoobotIdentityList[TheCurrentFoobot].name;
If Not Assigned(HLINI) then
HLINI:=TIniFile.Create(ChangeFileExt(GetAppConfigFile(False),'.ini'));
// Make sure the High-Lows are for the current Foobot
if (HLINI.ReadString('Foobot','CurrentFoobotName','unknown') <> sFoobotName)
then 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);
// 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);
// 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);
// 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);
// 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);
// 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);
end;
// ToDo: Multiple Foobots?
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);
begin
If aValue > FoobotDataHighs[iMember] then
begin
FoobotDataHighs[iMember]:=aValue;
FoobotDataHighTimes[iMember]:=aDateTime;
end;
end;
procedure SetLow(iMember:Integer;aValue:Variant;aDateTime:TDateTime);
begin
If (aValue < FoobotDataLows[iMember]) OR (FoobotDataLows[iMember] = 0) then
begin
FoobotDataLows[iMember]:=aValue;
FoobotDataLowTimes[iMember]:=aDateTime;
end;
end;
// ========== Internal routines end =============
begin
ResetArrays;
Result := True;
LoadHighLows;
if FoobotIdentityObject.FoobotIdentityList.Count = 0 then
Exit(False);
if FooBotDataObject.sensors.Count = 0 then
Exit(False);
if FooBotDataObject.units.Count = 0 then
Exit(False);
// J=Column, K=Row
for K := VarArrayLowBound(FoobotDataObject.datapoints, 1)
to VarArrayHighBound(FoobotDataObject.datapoints, 1) do
begin
for J := VarArrayLowBound(FoobotDataObject.datapoints[K], 1)
to VarArrayHighBound(FoobotDataObject.datapoints[K], 1) do
begin
Mydatapoint := FoobotDataObject.datapoints[K][J];
case J of
0: // First field is a DateTime
begin
iUnixSecs := int64(Mydatapoint);
SetLength(FoobotData_time, K + 1);
FoobotData_time[K] := UnixToDateTime(iUnixSecs);
end;
1: // 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
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
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
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
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
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;
end; // of Case
end;
end;
SaveHighLows;
end;
Function ResetHighLows:Boolean;
Var iCount:Integer;
begin
For iCount:=0 to HIGHLOWMAX do begin
FoobotDataHighs[iCount]:=0;
FoobotDataLows[iCount]:=0;
end;
Result:=TRUE;
end;
function ResetArrays: boolean;
begin
Result := True;
try
SetLength(FoobotData_time, 0);
SetLength(FoobotData_pm, 0);
SetLength(FoobotData_tmp, 0);
SetLength(FoobotData_hum, 0);
SetLength(FoobotData_co2, 0);
SetLength(FoobotData_voc, 0);
SetLength(FoobotData_allpollu, 0);
except
Result := False;
raise;
end;
end;
function ResetObjects: boolean;
var
J, K: integer;
begin
Result := True;
try
for K := VarArrayLowBound(FoobotDataObject.datapoints, 1)
to VarArrayHighBound(FoobotDataObject.datapoints, 1) do
for J := VarArrayLowBound(FoobotDataObject.datapoints[K], 1)
to VarArrayHighBound(FoobotDataObject.datapoints[K], 1) do
FoobotDataObject.datapoints[K][J] := 0;
FooBotDataObject.sensors.Clear;
FooBotDataObject.units.Clear;
FoobotIdentityObject.FoobotIdentityList.Clear;
except
Result := False;
raise;
end;
end;
function EncodeStringBase64(const s: string): string;
var
outstream: TStringStream;
encoder: TBase64EncodingStream;
begin
outstream := TStringStream.Create('');
try
encoder := TBase64EncodingStream.Create(outstream);
try
encoder.Write(s[1], length(s));
finally
encoder.Free;
end;
outstream.position := 0;
Result := outstream.readstring(outstream.size);
finally
outstream.Free;
end;
end;
function FetchAuthenticationKey(aUsername, aUserPassword: string): boolean;
var
sRequestURL: string;
iCount: integer;
begin
// FOOBOT_USER_URL = 'http://api.foobot.io/v2/user/%s/login/';
// sAuthenticationKey
// Looking for "x-auth-token"
Result := False;
try
with httpclient do
begin
ResponseHeaders.NameValueSeparator := ':';
AddHeader('Authorization', EncodeStringBase64(aUsername + ':' + aUserPassword));
sRequestURL := Format(FOOBOT_USER_URL, [aUsername]);
Get(sRequestURL);
if ResponseStatusCode <> 200 then
begin
ShowMessageFmt('Failed - Foobot server refused with code %d',
[ResponseStatusCode]);
Exit(False);
end;
for iCount := 0 to ResponseHeaders.Count do
ShowMessage(ResponseHeaders[iCount]);
Result := True;
end;
finally
end;
end;
function FetchFoobotIdentity(aUsername, aSecretKey: string): boolean;
var
sUserNameURL: string;
JSON: TJSONStringType;
DeStreamer: TJSONDeStreamer;
begin
Result := True; // Assume success: Look for failure
sAuthenticationKey:=aSecretKey;
try
with httpclient do
begin
DeStreamer := TJSONDeStreamer.Create(nil);
DeStreamer.Options := [jdoIgnorePropertyErrors];
sUserNameURL := Format(FOOBOT_IDENTITY_URL, [aUsername]);
ResponseHeaders.NameValueSeparator := ':';
AddHeader('Accept', 'application/json;charset=UTF-8');
AddHeader('X-API-KEY-TOKEN', aSecretKey);
JSON := Get(sUserNameURL);
if (ResponseStatusCode <> 200) then
case ResponseStatusCode of
429:
begin
ShowMessageFmt('Cannot retieve data - too many requests to the Foobot server%s%s',
[LineEnding, JSON]);
Exit(False);
end;
else
begin
ShowMessageFmt('Cannot retieve data - Foobot server refused with code %d',
[ResponseStatusCode]);
Exit(False);
end;
end;
try
// Stream it to the object list
DeStreamer.JSONToObject(JSON, FoobotIdentityObject.FoobotIdentityList);
except
On E: Exception do
showmessagefmt('Cannot retieve data - Foobot server refused with code %s', [E.Message]);
On E: Exception do
Result := False;
end;
end;
finally
DeStreamer.Free;
end;
end;
function FetchFoobotData(DataFetchType: TDataFetchType;
iCurrentFoobot, iLastIntervalSeconds, iLastAverageBySeconds: integer;
iStartTimeSeconds, iEndTimeSeconds: int64; aSecretKey: string): boolean;
var
sUserNameURL: string;
JSON: TJSONStringType;
DeStreamer: TJSONDeStreamer;
uuid: string;
//FOOBOT_DATA_LAST_URL = 'http://api.foobot.io/v2/device/%s/datapoint/%s/%s/%s/';
//FOOBOT_DATA_START_FINISH_URL = 'http://api.foobot.io/v2/device/%s/datapoint/%s/%s/%s/';
begin
Result := True; // Assume success: Look for failure
TheCurrentFoobot:=iCurrentFoobot;
// Checks for integrity
if (FoobotIdentityObject.FoobotIdentityList.Count = 0) then
Exit(False);
if (DataFetchType = dfStartEnd) and ((iStartTimeSeconds = 0) or
(iEndTimeSeconds = 0)) then
Exit(False);
if (aSecretKey = 'unknown') then
Exit(False);
try
with httpclient do
begin
DeStreamer := TJSONDeStreamer.Create(nil);
DeStreamer.Options := [jdoIgnorePropertyErrors];
// secretkey := INI.ReadString('Foobot', 'Secret Key', '');
uuid := FoobotIdentityObject.FoobotIdentityList.Items[iCurrentFoobot].uuid;
case DataFetchType of
dfLast:
sUserNameURL := Format(FOOBOT_DATA_LAST_URL,
[uuid, IntToStr(iLastIntervalSeconds), 'last',
IntToStr(iLastAverageBySeconds)]);
dfStartEnd:
sUserNameURL := Format(FOOBOT_DATA_START_FINISH_URL,
[uuid, IntToStr(iStartTimeSeconds), IntToStr(iEndTimeSeconds),
IntToStr(iLastAverageBySeconds)]);
else
begin
Result := False;
Exit;
end;
end;
ResponseHeaders.NameValueSeparator := ':';
AddHeader('Accept', 'application/json;charset=UTF-8');
AddHeader('X-API-KEY-TOKEN', aSecretKey);
JSON := Get(sUserNameURL);
if (ResponseStatusCode <> 200) then
case ResponseStatusCode of
429:
begin
ShowMessageFmt('Failed - Too many requests to the Foobot server%s%s',
[LineEnding, JSON]);
Exit(False);
end;
else
begin
ShowMessageFmt('Failed - Foobot server refused with code %d',
[ResponseStatusCode]);
Exit(False);
end;
end;
try
// Stream it to the object list
DeStreamer.JSONToObject(JSON, FoobotDataObject);
except
On E: Exception do
showmessagefmt('Failed - Foobot server refused with code %s', [E.Message]);
On E: Exception do
Result := False;
end;
end;
finally
DeStreamer.Free;
end;
end;
initialization
begin
HttpClient := TFPHTTPClient.Create(nil);
FoobotIdentityObject := TFoobotIdentityObject.Create;
FoobotDataObject := TFoobotDataObject.Create;
SaveLoadHighLows:=TRUE;
TheCurrentFoobot:=0;
end;
finalization
begin
If Assigned(HLINI) then FreeAndNil(HLINI);
FreeAndNil(HttpClient);
FreeAndNil(FoobotIdentityObject);
FreeAndNil(FoobotDataObject);
SetLength(FoobotData_time, 0);
SetLength(FoobotData_pm, 0);
SetLength(FoobotData_tmp, 0);
SetLength(FoobotData_hum, 0);
SetLength(FoobotData_co2, 0);
SetLength(FoobotData_voc, 0);
SetLength(FoobotData_allpollu, 0);
end;
end.

View File

@ -0,0 +1,63 @@
object dataform: Tdataform
Left = 840
Height = 425
Top = 140
Width = 668
BorderStyle = bsSingle
Caption = 'dataform'
ClientHeight = 425
ClientWidth = 668
OnCreate = FormCreate
OnShow = FormShow
Position = poMainFormCenter
LCLVersion = '1.7'
object grp_data: TGroupBox
Left = 0
Height = 368
Top = 0
Width = 668
Align = alTop
Caption = 'grp_data'
ClientHeight = 348
ClientWidth = 664
TabOrder = 0
object datagrid: TStringGrid
Left = 0
Height = 348
Top = 0
Width = 664
Align = alClient
AutoEdit = False
AutoFillColumns = True
ColCount = 7
ExtendedSelect = False
FixedCols = 0
Flat = True
HeaderHotZones = []
HeaderPushZones = []
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goSmoothScroll]
RowCount = 1
TabOrder = 0
ColWidths = (
94
94
94
94
94
94
99
)
end
end
object BitBtn1: TBitBtn
Left = 297
Height = 30
Top = 382
Width = 75
Anchors = [akBottom]
DefaultCaption = True
Kind = bkClose
ModalResult = 11
TabOrder = 1
end
end

View File

@ -0,0 +1,120 @@
unit udataform;
{ Foobot Interrogator data display
Copyright (C)2016 Gordon Bamber minsadorada@charcodelvalle.com
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Grids,
StdCtrls, Buttons, Variants, dateutils;
type
{ Tdataform }
Tdataform = class(TForm)
BitBtn1: TBitBtn;
datagrid: TStringGrid;
grp_data: TGroupBox;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
private
public
end;
var
dataform: Tdataform;
implementation
uses umainform,foobot_utility;
{$R *.lfm}
{ Tdataform }
procedure Tdataform.FormCreate(Sender: TObject);
begin
Icon := Application.Icon;
Caption := Application.Title + ' Data';
end;
procedure Tdataform.FormShow(Sender: TObject);
var
J, K, iCount: integer;
Mydatapoint: variant;
dtDate, dtStart, dtEnd: TDateTime;
sStart, sEnd: string;
iUnixSecs: int64;
begin
with mainform do
begin
dtStart := UnixToDateTime(FoobotDataObject.Start);
dtEnd := UnixToDateTime(FoobotDataObject.&end);
sStart := FormatDateTime('dd/mm tt', dtStart);
sEnd := FormatDateTime('dd/mm tt', dtEnd);
grp_data.Caption := 'Foobot ' +
FoobotIdentityObject.FoobotIdentityList.Items[CurrentFoobot].Name +
' From ' + sStart + ' to ' + sEnd;
if mainform.FetchType = dfLast then
grp_data.Caption := grp_data.Caption + ' Capture last = ' +
mainform.rg_interval.Items[mainform.rg_interval.ItemIndex] + ', ';
grp_data.Caption := grp_data.Caption + 'Average by = ' +
mainform.rg_intervalAverageBy.Items[mainform.rg_intervalAverageBy.ItemIndex] + ')';
for iCount := 0 to Pred(FoobotDataObject.sensors.Count) do
begin
datagrid.Cells[iCount, 0] :=
FoobotDataObject.sensors[iCount] + ' (' + FoobotDataObject.units[iCount] + ')';
end;
// J=Column, K=Row
for K := VarArrayLowBound(FoobotDataObject.datapoints, 1)
to VarArrayHighBound(FoobotDataObject.datapoints, 1) do
begin
for J := VarArrayLowBound(FoobotDataObject.datapoints[K], 1)
to VarArrayHighBound(FoobotDataObject.datapoints[K], 1) do
begin
Mydatapoint := FoobotDataObject.datapoints[K][J];
dataGrid.RowCount := K + 2;
if J = 0 then // First field is a DateTime
begin
if K = VarArrayHighBound(FoobotDataObject.datapoints, 1) then
datagrid.Cells[J, K + 1] := 'Latest' // Last entry is always latest
else
begin
iUnixSecs := int64(Mydatapoint);
dtDate := UnixToDateTime(iUnixSecs);
datagrid.Cells[J, K + 1] := FormatDateTime('dd/mm - tt', dtDate);
end;
end
else
datagrid.Cells[J, K + 1] := VarToStr(Mydatapoint);
end;
end;
end;
end;
end.

View File

@ -0,0 +1,50 @@
unit ugenericcollection;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils;
type
{ TGenericCollection }
generic TGenericCollection<T> = class(TCollection)
private
function GetItems(Index: integer): T;
procedure SetItems(Index: integer; AValue: T);
public
constructor Create;
public
function Add: T;
public
property Items[Index: integer]: T read GetItems write SetItems; default;
end;
implementation
{ TGenericCollection }
function TGenericCollection.GetItems(Index: integer): T;
begin
Result := T(inherited Items[Index]);
end;
procedure TGenericCollection.SetItems(Index: integer; AValue: T);
begin
Items[Index].Assign(AValue);
end;
constructor TGenericCollection.Create;
begin
inherited Create(T);
end;
function TGenericCollection.Add: T;
begin
Result := T(inherited Add);
end;
end.

View File

@ -0,0 +1,84 @@
object loginform: Tloginform
Left = 256
Height = 141
Top = 472
Width = 442
BorderIcons = [biSystemMenu]
BorderStyle = bsSingle
Caption = 'Foobot Login'
ClientHeight = 141
ClientWidth = 442
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
Position = poMainFormCenter
LCLVersion = '1.7'
Scaled = True
object GroupBox1: TGroupBox
Left = 0
Height = 88
Top = 0
Width = 442
Align = alTop
Caption = 'Your FooBot information'
ClientHeight = 68
ClientWidth = 438
TabOrder = 0
object edt_emailaddress: TLabeledEdit
Left = 16
Height = 23
Hint = 'This is your Foobot LogIn name'
Top = 24
Width = 192
EditLabel.AnchorSideLeft.Control = edt_emailaddress
EditLabel.AnchorSideRight.Control = edt_emailaddress
EditLabel.AnchorSideRight.Side = asrBottom
EditLabel.AnchorSideBottom.Control = edt_emailaddress
EditLabel.Left = 16
EditLabel.Height = 15
EditLabel.Top = 6
EditLabel.Width = 192
EditLabel.Caption = 'User Name (Email address)'
EditLabel.ParentColor = False
ParentShowHint = False
ShowHint = True
TabOrder = 0
Text = 'myname@myserver.com'
end
object edt_password: TLabeledEdit
Left = 230
Height = 23
Hint = 'This is your Foobot LogIn password'
Top = 24
Width = 192
EchoMode = emPassword
EditLabel.AnchorSideLeft.Control = edt_password
EditLabel.AnchorSideRight.Control = edt_password
EditLabel.AnchorSideRight.Side = asrBottom
EditLabel.AnchorSideBottom.Control = edt_password
EditLabel.Left = 230
EditLabel.Height = 15
EditLabel.Top = 6
EditLabel.Width = 192
EditLabel.Caption = 'Foobot password'
EditLabel.ParentColor = False
ParentShowHint = False
PasswordChar = '*'
ShowHint = True
TabOrder = 1
Text = 'mypassword'
end
end
object cmd_OK: TBitBtn
Left = 184
Height = 30
Top = 96
Width = 75
Anchors = [akLeft, akRight, akBottom]
Default = True
DefaultCaption = True
Kind = bkOK
ModalResult = 1
OnClick = cmd_OKClick
TabOrder = 1
end
end

View File

@ -0,0 +1,109 @@
unit ulogin;
{ Foobot Interrogator
Copyright (C)2016 Gordon Bamber minsadorada@charcodelvalle.com
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ExtCtrls, Buttons;
type
{ Tloginform }
Tloginform = class(TForm)
cmd_OK: TBitBtn;
edt_emailaddress: TLabeledEdit;
edt_password: TLabeledEdit;
GroupBox1: TGroupBox;
procedure cmd_OKClick(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
procedure FormCreate(Sender: TObject);
private
function ValidEmail(sEmail: string): boolean;
public
end;
var
loginform: Tloginform;
implementation
{$R *.lfm}
uses umainform;
{ Tloginform }
procedure Tloginform.FormCreate(Sender: TObject);
begin
Icon := Application.Icon;
Caption := Application.Title + ' Login';
edt_emailaddress.Text := mainform.INI.ReadString('Foobot', 'Foobot User',
'myname@myserver.com');
edt_password.Text := mainform.INI.ReadString('Foobot', 'Foobot Password', 'password');
end;
procedure Tloginform.cmd_OKClick(Sender: TObject);
begin
Close;
end;
procedure Tloginform.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
if not ValidEmail(edt_emailaddress.Text) then
begin
MessageDlg(Application.Title, edt_emailaddress.Text + LineEnding +
' is not a valid email address', mtError, [mbOK], 0);
CanClose := False;
end
else
CanClose := True;
mainform.INI.WriteString('Foobot', 'Foobot User', edt_emailaddress.Text);
mainform.INI.WriteString('Foobot', 'Foobot Password', edt_password.Text);
end;
function Tloginform.ValidEmail(sEmail: string): boolean;
var
at, dot, i: integer;
bOkay: boolean;
begin
at := Pos('@', sEmail);
dot := LastDelimiter('.', sEmail);
bOkay := (at > 0) and (dot > at);
if bOkay then
begin
for i := 1 to Length(sEmail) do
begin
if not (sEmail[i] in ['a'..'z', 'A'..'Z', '0'..'9', '-', '_', '.', '@']) then
begin
bOkay := False;
break;
end;
end;
end;
Result := bOkay;
end;
end.

View File

@ -0,0 +1,262 @@
object mainform: Tmainform
Left = 547
Height = 377
Top = 198
Width = 510
BorderIcons = [biSystemMenu, biMinimize]
BorderStyle = bsSingle
Caption = 'mainform'
ClientHeight = 357
ClientWidth = 510
DefaultMonitor = dmDesktop
Menu = MainMenu1
OnCreate = FormCreate
OnDestroy = FormDestroy
OnShow = FormShow
Position = poScreenCenter
LCLVersion = '1.7'
Scaled = True
object GroupBox3: TGroupBox
Left = 0
Height = 209
Top = 0
Width = 510
Align = alTop
Caption = 'Your Foobots'
ClientHeight = 189
ClientWidth = 506
TabOrder = 0
object tv_Identity: TTreeView
Left = 0
Height = 136
Top = 53
Width = 506
Align = alBottom
AutoExpand = True
DefaultItemHeight = 18
ExpandSignType = tvestPlusMinus
MultiSelectStyle = [msVisibleOnly]
ReadOnly = True
RowSelect = True
ShowLines = False
ShowRoot = False
TabOrder = 0
OnClick = tv_IdentityClick
Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoRowSelect, tvoShowButtons, tvoToolTips, tvoThemedDraw]
end
object cmd_GetIdentity: TButton
Left = 8
Height = 30
Hint = 'Click to fetch your Foobot details'
Top = 8
Width = 128
Caption = 'Fetch all Foobots'
OnClick = cmd_GetIdentityClick
ParentShowHint = False
ShowHint = True
TabOrder = 1
end
object cmd_FetchData: TButton
Left = 144
Height = 30
Top = 8
Width = 248
Caption = 'Fetch data from selected Foobot'
Enabled = False
OnClick = cmd_FetchDataClick
ParentFont = False
TabOrder = 2
end
object cmd_Close: TBitBtn
Left = 422
Height = 30
Top = 8
Width = 75
Anchors = []
DefaultCaption = True
Kind = bkClose
ModalResult = 11
OnClick = mnu_fileExitClick
TabOrder = 3
end
end
object sb: TStatusBar
Left = 0
Height = 23
Top = 334
Width = 510
Panels = <>
end
object rg_interval: TRadioGroup
Left = 264
Height = 105
Top = 216
Width = 96
AutoFill = True
Caption = 'Previous...'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 85
ClientWidth = 92
Enabled = False
ItemIndex = 0
Items.Strings = (
'Now'
'Hour'
'2 Hours'
'4 Hours'
'8 Hours'
)
OnSelectionChanged = rg_intervalSelectionChanged
TabOrder = 2
end
object rg_intervalAverageBy: TRadioGroup
Left = 360
Height = 105
Top = 216
Width = 145
AutoFill = True
Caption = 'Average by..'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 85
ClientWidth = 141
Enabled = False
ItemIndex = 0
Items.Strings = (
'No average'
'Hourly average'
'8-Hourly average'
'24-Hourly average'
'Total average'
)
OnSelectionChanged = rg_intervalAverageBySelectionChanged
TabOrder = 3
end
object rg_mode: TRadioGroup
Left = 8
Height = 105
Top = 216
Width = 112
AutoFill = True
Caption = 'Mode'
ChildSizing.LeftRightSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1
ClientHeight = 85
ClientWidth = 108
Enabled = False
ItemIndex = 0
Items.Strings = (
'Previous'
'Date Range'
)
OnSelectionChanged = rg_modeSelectionChanged
TabOrder = 4
end
object grp_daterange: TGroupBox
Left = 128
Height = 105
Top = 216
Width = 129
Caption = 'Date Range'
ClientHeight = 85
ClientWidth = 125
Enabled = False
TabOrder = 5
object lbl_fromdate: TLabel
Left = 8
Height = 15
Top = 12
Width = 55
Caption = 'From Date'
ParentColor = False
end
object lbl_to: TLabel
Left = 8
Height = 15
Top = 36
Width = 11
Caption = 'to'
ParentColor = False
end
object lbl_toDate: TLabel
Left = 8
Height = 15
Top = 60
Width = 39
Caption = 'To date'
ParentColor = False
end
object spd_fromdate: TSpeedButton
Left = 88
Height = 22
Top = 8
Width = 23
Caption = '...'
OnClick = spd_fromdateClick
end
object spd_todate: TSpeedButton
Left = 88
Height = 22
Top = 56
Width = 23
Caption = '...'
OnClick = spd_todateClick
end
end
object Button1: TButton
Left = 0
Height = 25
Top = 312
Width = 75
Caption = 'Button1'
OnClick = Button1Click
TabOrder = 6
end
object MainMenu1: TMainMenu
Left = 304
Top = 24
object mnu_file: TMenuItem
Caption = '&File'
object mnu_fileExit: TMenuItem
Caption = 'E&xit'
OnClick = mnu_fileExitClick
end
end
object mnu_help: TMenuItem
Caption = '&Help'
object mnu_helpAbout: TMenuItem
Caption = '&About...'
OnClick = mnu_helpAboutClick
end
end
end
object ApplicationProperties1: TApplicationProperties
ExceptionDialog = aedOkMessageBox
OnHint = ApplicationProperties1Hint
Left = 264
Top = 16
end
object CalendarDialog1: TCalendarDialog
Date = 42730
OKCaption = '&OK'
CancelCaption = 'Cancel'
Left = 373
Top = 25
end
end

View File

@ -0,0 +1,346 @@
unit umainform;
{ Foobot Interrogator
Copyright (C)2016 Gordon Bamber minsadorada@charcodelvalle.com
This source is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This code is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
A copy of the GNU General Public License is available on the World Wide Web
at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing
to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.
}
{
== VERSION HISTORY ==
V0.1.0.0: Intial version by minesadorada
V0.1.1.0: ??
}
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
Buttons, Menus, ExtCtrls, ComCtrls, ExtDlgs,
ucryptini, dateutils, ulogin, udataform, foobot_utility;
type
{ Tmainform }
Tmainform = class(TForm)
ApplicationProperties1: TApplicationProperties;
Button1: TButton;
CalendarDialog1: TCalendarDialog;
cmd_Close: TBitBtn;
cmd_FetchData: TButton;
cmd_GetIdentity: TButton;
grp_daterange: TGroupBox;
GroupBox3: TGroupBox;
lbl_fromdate: TLabel;
lbl_to: TLabel;
lbl_toDate: TLabel;
MainMenu1: TMainMenu;
mnu_helpAbout: TMenuItem;
mnu_help: TMenuItem;
mnu_fileExit: TMenuItem;
mnu_file: TMenuItem;
rg_intervalAverageBy: TRadioGroup;
rg_interval: TRadioGroup;
rg_mode: TRadioGroup;
sb: TStatusBar;
spd_fromdate: TSpeedButton;
spd_todate: TSpeedButton;
tv_Identity: TTreeView;
procedure ApplicationProperties1Hint(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure cmd_FetchDataClick(Sender: TObject);
procedure cmd_GetIdentityClick(Sender: TObject);
procedure cmd_testClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure mnu_fileExitClick(Sender: TObject);
procedure mnu_helpAboutClick(Sender: TObject);
procedure rg_intervalAverageBySelectionChanged(Sender: TObject);
procedure rg_intervalSelectionChanged(Sender: TObject);
procedure rg_modeSelectionChanged(Sender: TObject);
procedure spd_fromdateClick(Sender: TObject);
procedure spd_todateClick(Sender: TObject);
procedure tv_IdentityClick(Sender: TObject);
private
sFoobotUserName: string;
sFoobotPassword: string;
iLastIntervalSeconds: integer;
iLastAverageBySeconds: integer;
iStartTimeSeconds, iEndTimeSeconds: int64;
function PopulateIdentityTreeView: boolean;
public
INI: TCryptIniFile;
CurrentFoobot: integer;
FetchType: TDataFetchType;
end;
var
mainform: Tmainform;
implementation
{$R *.lfm}
{ Tmainform }
procedure Tmainform.FormCreate(Sender: TObject);
begin
Icon := Application.Icon;
Caption := Application.Title;
INI := TCryptINIFile.Create(GetAppConfigFile(False));
if INI.IsVirgin then
begin
INI.WriteIdent('Gordon Bamber', '(c)2016', 'GPLV2',
'minesadorada@charcodelvalle.com', True);
// PUT YOUR SECRET API KEY HERE IF YOU LIKE
// INI.WriteString('Foobot', 'Secret Key',
'');
end;
if not INI.VerifyIdent('41d10218d247980fc5e871b6b7844483') then
begin
ShowMessage(Application.Title +
' has been tampered wth. Please re-install from a trusted source.');
Application.Terminate;
end;
CurrentFoobot := 0;
Hint := 'Welcome to ' + Application.Title;
sb.SimpleText := Hint;
FetchType := dfLast;
end;
procedure Tmainform.FormDestroy(Sender: TObject);
begin
FreeAndNil(INI);
end;
procedure Tmainform.FormShow(Sender: TObject);
begin
loginform.showmodal;
sFoobotUserName := INI.ReadString('Foobot', 'Foobot User', 'myname@myserver.com');
sFoobotPassword := INI.ReadString('Foobot', 'Foobot Password', 'password');
end;
procedure Tmainform.cmd_testClick(Sender: TObject);
begin
end;
function Tmainform.PopulateIdentityTreeView: boolean;
var
iCount: integer;
mainnode, node: TTreeNode;
begin
Result := False;
if FoobotIdentityObject.FoobotIdentityList.Count > 0 then
begin
// TTreeView
TV_Identity.Items.Add(nil, 'All Foobots'); // Root
try
// Loop through all the detected Foobot instances
for iCount := 0 to Pred(FoobotIdentityObject.FoobotIdentityList.Count) do
begin
mainnode := TV_Identity.Items[iCount];
node := TV_Identity.Items.AddChild(mainnode,
Format('Foobot #%d', [Succ(iCount)]));
TV_Identity.Items.AddChild(node, 'Name: ' +
FoobotIdentityObject.FoobotIdentityList.Items[iCount].Name);
TV_Identity.Items.AddChild(node, 'UserID: ' +
Format('%d', [FoobotIdentityObject.FoobotIdentityList.Items[
iCount].userID]));
TV_Identity.Items.AddChild(node, 'Mac: ' +
FoobotIdentityObject.FoobotIdentityList.Items[iCount].mac);
TV_Identity.Items.AddChild(node, 'uuID: ' +
FoobotIdentityObject.FoobotIdentityList.Items[iCount].uuid);
node.Expanded := False;
Result := True;
end;
except
On E: Exception do
showmessagefmt('PopulateIdentityTreeView: Failed because %s', [E.Message]);
end;
end;
end;
procedure Tmainform.cmd_GetIdentityClick(Sender: TObject);
var
sSecretKey: string;
begin
sSecretKey := INI.ReadString('Foobot', 'Secret Key', '');
if FetchFoobotIdentity(sFoobotUserName, sSecretKey) then
if PopulateIdentityTreeView then
begin
cmd_GetIdentity.Enabled := False;
tv_Identity.Hint := 'Click on a Foobot instance in the panel to interrogate it';
tv_Identity.ShowHint := True;
end;
end;
procedure Tmainform.ApplicationProperties1Hint(Sender: TObject);
begin
if Application.Hint <> '' then
sb.SimpleText := Application.Hint
else
sb.SimpleText := mainform.hint;
end;
procedure Tmainform.Button1Click(Sender: TObject);
begin
FetchAuthenticationKey(sFoobotUserName, sFoobotPassword);
end;
procedure Tmainform.cmd_FetchDataClick(Sender: TObject);
var
sSecretKey: string;
begin
sSecretKey := INI.ReadString('Foobot', 'Secret Key', '');
if FetchFoobotData(FetchType, CurrentFoobot, iLastIntervalSeconds,
iLastAverageBySeconds, iStartTimeSeconds, iEndTimeSeconds, sSecretKey) then
begin
//DEBUG FoobotDataObject.SaveToFile('FoobotDataObject.json');
dataform.ShowModal;
end;
end;
procedure Tmainform.mnu_fileExitClick(Sender: TObject);
begin
Close;
end;
procedure Tmainform.mnu_helpAboutClick(Sender: TObject);
var
s: string;
begin
s := Application.Title + LineEnding;
s += 'Version: ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_APPVERSION, '') +
LineEnding + LineEnding;
s += INI.ReadUnencryptedString('ProgramInfo', IDENT_COPYRIGHT, '');
s += ' by ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_AUTHOR, '') + LineEnding;
s += 'Licence: ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_LICENSE, '') +
LineEnding;
s += 'Made with LCL v ' + INI.ReadUnencryptedString('ProgramInfo',
IDENT_LCLVERSION, '');
s += ' FPC v ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_FPCVERSION, '') +
LineEnding;
s += 'Compiled ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_LASTCOMPILED, '') +
LineEnding;
s += ' for ' + INI.ReadUnencryptedString('ProgramInfo', IDENT_TARGET, '');
MessageDlg('About ' + Application.Title, s,
mtInformation, [mbOK], 0);
end;
procedure Tmainform.rg_intervalAverageBySelectionChanged(Sender: TObject);
begin
case rg_intervalAverageBy.ItemIndex of
0:
begin
if FetchType = dfStartEnd then
begin
MessageDlg(Application.Title, 'Setting minimum average = Hourly',
mtError, [mbOK], 0);
iLastAverageBySeconds := 3600;
end
else
iLastAverageBySeconds := 0;
end;
1: iLastAverageBySeconds := 3600;
2: iLastAverageBySeconds := 8 * 3600;
3: iLastAverageBySeconds := 24 * 3600;
4: iLastAverageBySeconds := iLastIntervalSeconds;
end;
end;
procedure Tmainform.rg_intervalSelectionChanged(Sender: TObject);
begin
case rg_interval.ItemIndex of
0: iLastIntervalSeconds := 0;
1: iLastIntervalSeconds := 3600;
2: iLastIntervalSeconds := 2 * 3600;
3: iLastIntervalSeconds := 4 * 3600;
4: iLastIntervalSeconds := 8 * 3600;
end;
end;
procedure Tmainform.rg_modeSelectionChanged(Sender: TObject);
begin
case rg_mode.ItemIndex of
0:
begin
FetchType := dfLast;
rg_interval.Enabled := True;
grp_daterange.Enabled := False;
end;
1:
begin
FetchType := dfStartEnd;
rg_interval.Enabled := False;
grp_daterange.Enabled := True;
end;
end;
end;
procedure Tmainform.spd_fromdateClick(Sender: TObject);
begin
if CalendarDialog1.Execute then
begin
iStartTimeSeconds := DateTimeToUnix(CalendarDialog1.Date);
lbl_fromdate.Caption := FormatDateTime('dd/mm/yyyy', CalendarDialog1.Date);
end;
end;
procedure Tmainform.spd_todateClick(Sender: TObject);
begin
if CalendarDialog1.Execute then
begin
iEndTimeSeconds := DateTimeToUnix(CalendarDialog1.Date);
lbl_todate.Caption := FormatDateTime('dd/mm/yyyy', CalendarDialog1.Date);
end;
end;
procedure Tmainform.tv_IdentityClick(Sender: TObject);
var
node: TTreeNode;
begin
if tv_Identity.Items.Count > 0 then
begin
node := tv_Identity.Selected;
if not Assigned(Node) then
Exit;
if node.Level = 1 then
begin
CurrentFoobot := node.Index; // Zero-based
cmd_FetchData.Enabled := True;
cmd_FetchData.Font.Style := [fsBold];
rg_mode.Enabled := True;
rg_interval.Enabled := True;
rg_intervalAverageBy.Enabled := True;
end
else
begin
cmd_FetchData.Enabled := False;
cmd_FetchData.Font.Style := [];
end;
end;
end;
end.

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -0,0 +1,278 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="10"/>
<PathDelim Value="\"/>
<General>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="Foobot monitor"/>
<UseAppBundle Value="False"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<XPManifest>
<DpiAware Value="True"/>
<TextName Value="CompanyName.ProductName.AppName"/>
<TextDesc Value="Your application description."/>
</XPManifest>
<Icon Value="0"/>
</General>
<VersionInfo>
<UseVersionInfo Value="True"/>
<RevisionNr Value="1"/>
</VersionInfo>
<BuildModes Count="6">
<Item1 Name="Debug" Default="True"/>
<Item2 Name="win32">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\$(BuildMode)\foobotmonitor"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value=".."/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<TargetCPU Value="i386"/>
<TargetOS Value="win32"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
</Item2>
<Item3 Name="win64">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\$(BuildMode)\foobotmonitor"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value=".."/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<TargetCPU Value="x86_64"/>
<TargetOS Value="win64"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
</Item3>
<Item4 Name="linux32">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\$(BuildMode)\foobotmonitor"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value=".."/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<TargetCPU Value="i386"/>
<TargetOS Value="linux"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
</Item4>
<Item5 Name="linux64">
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\$(BuildMode)\foobotmonitor"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value=".."/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<TargetCPU Value="x86_64"/>
<TargetOS Value="linux"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
</Item5>
<Item6 Name="win32GTK2">
<MacroValues Count="1">
<Macro1 Name="LCLWidgetType" Value="gtk2"/>
</MacroValues>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\$(BuildMode)\foobotmonitor"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value=".."/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<CodeGeneration>
<TargetCPU Value="i386"/>
<TargetOS Value="win32"/>
</CodeGeneration>
<Linking>
<Debugging>
<GenerateDebugInfo Value="False"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
</Item6>
<SharedMatrixOptions Count="1">
<Item1 ID="571324092942" Modes="win32GTK2" Type="IDEMacro" MacroName="LCLWidgetType" Value="gtk2"/>
</SharedMatrixOptions>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
</local>
</RunParams>
<RequiredPackages Count="3">
<Item1>
<PackageName Value="industrial"/>
</Item1>
<Item2>
<PackageName Value="cryptini"/>
</Item2>
<Item3>
<PackageName Value="LCL"/>
</Item3>
</RequiredPackages>
<Units Count="7">
<Unit0>
<Filename Value="foobotmonitor.lpr"/>
<IsPartOfProject Value="True"/>
</Unit0>
<Unit1>
<Filename Value="umainform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="mainform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit1>
<Unit2>
<Filename Value="uconfigform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="configform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit2>
<Unit3>
<Filename Value="..\foobot_httpclient.pas"/>
<IsPartOfProject Value="True"/>
</Unit3>
<Unit4>
<Filename Value="..\foobot_objects.pas"/>
<IsPartOfProject Value="True"/>
</Unit4>
<Unit5>
<Filename Value="..\foobot_utility.pas"/>
<IsPartOfProject Value="True"/>
</Unit5>
<Unit6>
<Filename Value="..\ugenericcollection.pas"/>
<IsPartOfProject Value="True"/>
</Unit6>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<PathDelim Value="\"/>
<Target>
<Filename Value="compiled\$(BuildMode)\foobotmonitor"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value=".."/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<IncludeAssertionCode Value="True"/>
</SyntaxOptions>
</Parsing>
<CodeGeneration>
<Checks>
<IOChecks Value="True"/>
<RangeChecks Value="True"/>
<OverflowChecks Value="True"/>
<StackChecks Value="True"/>
</Checks>
<VerifyObjMethodCallValidity Value="True"/>
</CodeGeneration>
<Linking>
<Debugging>
<UseHeaptrc Value="True"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -0,0 +1,31 @@
program foobotmonitor;
{$ifdef Linux}
{$ifdef FPC_CROSSCOMPILING}
{$ifdef CPUARM}
//if GUI, then uncomment
//{$linklib GLESv2}
{$endif}
{$linklib libc_nonshared.a}
{$endif}
{$endif}
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, umainform, uconfigform
{ you can add units after this };
{$R *.res}
begin
Application.Title:='Foobot monitor';
RequireDerivedFormResource:=True;
Application.Initialize;
Application.CreateForm(Tmainform, mainform);
Application.CreateForm(Tconfigform, configform);
Application.Run;
end.

View File

@ -0,0 +1,237 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectSession>
<PathDelim Value="\"/>
<Version Value="10"/>
<BuildModes Active="win64"/>
<Units Count="19">
<Unit0>
<Filename Value="foobotmonitor.lpr"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="7"/>
<CursorPos X="33" Y="25"/>
<UsageCount Value="38"/>
<Loaded Value="True"/>
</Unit0>
<Unit1>
<Filename Value="umainform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="mainform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<TopLine Value="80"/>
<CursorPos X="54" Y="105"/>
<UsageCount Value="38"/>
<Loaded Value="True"/>
<LoadedDesigner Value="True"/>
</Unit1>
<Unit2>
<Filename Value="uconfigform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="configform"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<EditorIndex Value="1"/>
<TopLine Value="80"/>
<CursorPos X="23" Y="92"/>
<UsageCount Value="28"/>
<Loaded Value="True"/>
</Unit2>
<Unit3>
<Filename Value="..\foobot_httpclient.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="20"/>
</Unit3>
<Unit4>
<Filename Value="..\foobot_objects.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="20"/>
</Unit4>
<Unit5>
<Filename Value="..\foobot_utility.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<TopLine Value="74"/>
<CursorPos X="21" Y="138"/>
<UsageCount Value="20"/>
</Unit5>
<Unit6>
<Filename Value="..\ugenericcollection.pas"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="20"/>
</Unit6>
<Unit7>
<Filename Value="..\latest_stable\foobot_httpclient.pas"/>
<EditorIndex Value="3"/>
<TopLine Value="260"/>
<CursorPos X="8" Y="1048"/>
<UsageCount Value="38"/>
<Loaded Value="True"/>
</Unit7>
<Unit8>
<Filename Value="..\latest_stable\foobot_objects.pas"/>
<EditorIndex Value="6"/>
<CursorPos X="32" Y="61"/>
<UsageCount Value="38"/>
<Loaded Value="True"/>
</Unit8>
<Unit9>
<Filename Value="..\foobot_utility.pas"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="5"/>
<TopLine Value="85"/>
<CursorPos X="72" Y="104"/>
<UsageCount Value="38"/>
<Loaded Value="True"/>
</Unit9>
<Unit10>
<Filename Value="..\latest_stable\ugenericcollection.pas"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="38"/>
</Unit10>
<Unit11>
<Filename Value="..\latest_stable\umainform.lfm"/>
<EditorIndex Value="-1"/>
<UsageCount Value="10"/>
<DefaultSyntaxHighlighter Value="LFM"/>
</Unit11>
<Unit12>
<Filename Value="..\latest_stable\umainform.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="10"/>
<CursorPos X="57" Y="36"/>
<UsageCount Value="10"/>
</Unit12>
<Unit13>
<Filename Value="..\udataform.pas"/>
<EditorIndex Value="8"/>
<TopLine Value="74"/>
<CursorPos Y="96"/>
<UsageCount Value="18"/>
<Loaded Value="True"/>
</Unit13>
<Unit14>
<Filename Value="..\umainform.pas"/>
<EditorIndex Value="4"/>
<TopLine Value="134"/>
<CursorPos X="25" Y="154"/>
<UsageCount Value="18"/>
<Loaded Value="True"/>
</Unit14>
<Unit15>
<Filename Value="C:\trunklatest\lazarus\lcl\lclmessageglue.pas"/>
<UnitName Value="LCLMessageGlue"/>
<EditorIndex Value="-1"/>
<TopLine Value="93"/>
<CursorPos Y="114"/>
<UsageCount Value="10"/>
</Unit15>
<Unit16>
<Filename Value="..\ulogin.pas"/>
<EditorIndex Value="2"/>
<TopLine Value="65"/>
<CursorPos Y="108"/>
<UsageCount Value="13"/>
<Loaded Value="True"/>
</Unit16>
<Unit17>
<Filename Value="..\..\..\components\cryptini\latest_stable\ucryptini.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="906"/>
<CursorPos X="8" Y="939"/>
<UsageCount Value="11"/>
</Unit17>
<Unit18>
<Filename Value="..\backup\foobot_utility.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="7"/>
<UsageCount Value="10"/>
</Unit18>
</Units>
<JumpHistory Count="17" HistoryIndex="16">
<Position1>
<Filename Value="umainform.pas"/>
<Caret Line="7" Column="9"/>
</Position1>
<Position2>
<Filename Value="umainform.pas"/>
<Caret Line="188" Column="3" TopLine="186"/>
</Position2>
<Position3>
<Filename Value="umainform.pas"/>
<Caret Line="189" Column="3" TopLine="187"/>
</Position3>
<Position4>
<Filename Value="umainform.pas"/>
<Caret Line="190" Column="3" TopLine="188"/>
</Position4>
<Position5>
<Filename Value="umainform.pas"/>
<Caret Line="191" Column="3" TopLine="189"/>
</Position5>
<Position6>
<Filename Value="umainform.pas"/>
<Caret Line="192" Column="3" TopLine="190"/>
</Position6>
<Position7>
<Filename Value="umainform.pas"/>
<Caret Line="193" Column="3" TopLine="191"/>
</Position7>
<Position8>
<Filename Value="umainform.pas"/>
<Caret Line="15" Column="3" TopLine="4"/>
</Position8>
<Position9>
<Filename Value="umainform.pas"/>
<Caret Line="13" Column="15"/>
</Position9>
<Position10>
<Filename Value="umainform.pas"/>
<Caret Line="14" Column="6"/>
</Position10>
<Position11>
<Filename Value="umainform.pas"/>
<Caret Line="208" TopLine="204"/>
</Position11>
<Position12>
<Filename Value="umainform.pas"/>
<Caret Line="216" TopLine="212"/>
</Position12>
<Position13>
<Filename Value="umainform.pas"/>
<Caret Line="223" Column="28" TopLine="220"/>
</Position13>
<Position14>
<Filename Value="umainform.pas"/>
<Caret Line="236" Column="29" TopLine="233"/>
</Position14>
<Position15>
<Filename Value="umainform.pas"/>
<Caret Line="163" Column="48" TopLine="143"/>
</Position15>
<Position16>
<Filename Value="umainform.pas"/>
<Caret Line="165" Column="48" TopLine="145"/>
</Position16>
<Position17>
<Filename Value="umainform.pas"/>
<Caret Line="153" Column="47" TopLine="132"/>
</Position17>
</JumpHistory>
</ProjectSession>
</CONFIG>

Binary file not shown.

View File

@ -0,0 +1,89 @@
object configform: Tconfigform
Left = 654
Height = 197
Top = 285
Width = 592
BorderIcons = []
BorderStyle = bsToolWindow
Caption = 'configform'
ClientHeight = 197
ClientWidth = 592
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
Position = poMainFormCenter
LCLVersion = '1.7'
object grp_main: TGroupBox
Left = 0
Height = 145
Top = 0
Width = 592
Align = alTop
Caption = 'Your Foobot'
ClientHeight = 125
ClientWidth = 588
TabOrder = 0
object edt_username: TLabeledEdit
Left = 104
Height = 23
Top = 8
Width = 472
EditLabel.AnchorSideTop.Control = edt_username
EditLabel.AnchorSideTop.Side = asrCenter
EditLabel.AnchorSideRight.Control = edt_username
EditLabel.AnchorSideBottom.Control = edt_username
EditLabel.AnchorSideBottom.Side = asrBottom
EditLabel.Left = 7
EditLabel.Height = 15
EditLabel.Top = 12
EditLabel.Width = 94
EditLabel.Caption = 'Foobot Username'
EditLabel.ParentColor = False
LabelPosition = lpLeft
TabOrder = 0
Text = '(email address)'
OnEditingDone = edt_usernameEditingDone
end
object Memo1: TMemo
Left = 0
Height = 69
Top = 56
Width = 588
Align = alBottom
Lines.Strings = (
'Copy + Paste here'
)
OnEditingDone = Memo1EditingDone
TabOrder = 1
end
object Label1: TLabel
Left = 8
Height = 15
Top = 32
Width = 75
Caption = 'API Secret Key'
ParentColor = False
end
end
object BitBtn1: TBitBtn
Left = 259
Height = 30
Top = 160
Width = 75
Default = True
DefaultCaption = True
Kind = bkOK
ModalResult = 1
TabOrder = 1
end
object BitBtn2: TBitBtn
Left = 512
Height = 30
Top = 160
Width = 75
Cancel = True
DefaultCaption = True
Kind = bkCancel
ModalResult = 11
TabOrder = 2
end
end

View File

@ -0,0 +1,124 @@
unit uconfigform;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ExtCtrls, Buttons;
type
{ Tconfigform }
Tconfigform = class(TForm)
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
grp_main: TGroupBox;
edt_username: TLabeledEdit;
Label1: TLabel;
Memo1: TMemo;
procedure edt_usernameEditingDone(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
procedure FormCreate(Sender: TObject);
procedure Memo1EditingDone(Sender: TObject);
private
bDoneUsername,bDoneSecretKey:Boolean;
function ValidEmail(sEmail: string): boolean;
public
FoobotUsername,FoobotSecretKey:String;
bValid:Boolean;
end;
var
configform: Tconfigform;
implementation
Uses umainform;
{$R *.lfm}
{ Tconfigform }
function Tconfigform.ValidEmail(sEmail: string): boolean;
var
at, dot, i: integer;
bOkay: boolean;
begin
at := Pos('@', sEmail);
dot := LastDelimiter('.', sEmail);
bOkay := (at > 0) and (dot > at);
if bOkay then
begin
for i := 1 to Length(sEmail) do
begin
if not (sEmail[i] in ['a'..'z', 'A'..'Z', '0'..'9', '-', '_', '.', '@']) then
begin
bOkay := False;
break;
end;
end;
end;
Result := bOkay;
end;
procedure Tconfigform.FormCreate(Sender: TObject);
begin
Caption:='Configure ' + Application.Title;
Icon:=Application.Icon;
bDoneUsername:=FALSE;
bDoneSecretKey:=FALSE;
bValid:=False;
FoobotUsername:= mainform.INI.ReadString('Foobot', 'Foobot User', 'unknown');
FoobotSecretKey:= mainform.INI.ReadString('Foobot', 'Secret Key', 'unknown');
end;
procedure Tconfigform.Memo1EditingDone(Sender: TObject);
begin
If (Memo1.Text='Copy + Paste here') then
begin
MessageDlg(Application.Title,
edt_username.Text + ' is not a valid API key. Try again',
mtWarning,[MBOK],0);
Exit;
end
else
FoobotSecretKey:=Memo1.Text;
bDoneSecretKey:=TRUE;
end;
procedure Tconfigform.edt_usernameEditingDone(Sender: TObject);
begin
If NOT ValidEmail(edt_username.Text) then
begin
MessageDlg(Application.Title,
edt_username.Text + ' is not a valid email address. Try again',
mtWarning,[MBOK],0);
Exit;
end
else
begin
FoobotUsername:=edt_username.Text;
bDoneUsername:=TRUE;
end;
end;
procedure Tconfigform.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
If ( bDoneUsername=FALSE) OR (bDoneSecretKey=FALSE) then
begin
CanClose:=FALSE;
If MessageDlg('You haven''t completed all the fields. Are you sure you want to quit?',
mtConfirmation,[MBYES,MBNO],0,MBNO) = mrYes then CanClose:=TRUE;
end
else
begin
bValid:=TRUE;
CanClose:=TRUE;
end;
end;
end.

View File

@ -0,0 +1,383 @@
object mainform: Tmainform
Left = 615
Height = 262
Top = 154
Width = 782
BorderIcons = [biSystemMenu]
BorderStyle = bsToolWindow
Caption = 'mainform'
ClientHeight = 242
ClientWidth = 782
DefaultMonitor = dmDesktop
Menu = MainMenu1
OnActivate = FormActivate
OnCreate = FormCreate
OnDestroy = FormDestroy
OnShow = FormShow
Position = poWorkAreaCenter
LCLVersion = '1.7'
Scaled = True
object grp_sensorDisplay: TGroupBox
Left = 0
Height = 120
Top = 0
Width = 782
Align = alTop
Caption = 'Current Values'
ChildSizing.ControlsPerLine = 6
ClientHeight = 100
ClientWidth = 778
TabOrder = 0
object as_pm: TAnalogSensor
Left = 0
Height = 100
Top = 0
Width = 130
Align = alLeft
ClientHeight = 100
ClientWidth = 130
TabOrder = 0
ShowText = True
ShowLevel = True
Value = 0
ValueMin = 0
ValueMax = 300
ValueRed = 0
ValueYellow = 0
AnalogKind = akAnalog
end
object as_tmp: TAnalogSensor
Left = 130
Height = 100
Top = 0
Width = 130
Align = alLeft
ClientHeight = 100
ClientWidth = 130
TabOrder = 1
ShowText = True
ShowLevel = True
Value = 0
ValueMin = 0
ValueMax = 40
ValueRed = 0
ValueYellow = 0
AnalogKind = akAnalog
end
object as_hum: TAnalogSensor
Left = 260
Height = 100
Top = 0
Width = 130
Align = alLeft
ClientHeight = 100
ClientWidth = 130
TabOrder = 2
ShowText = True
ShowLevel = True
Value = 0
ValueMin = 0
ValueMax = 100
ValueRed = 0
ValueYellow = 0
AnalogKind = akAnalog
end
object as_co2: TAnalogSensor
Left = 390
Height = 100
Top = 0
Width = 130
Align = alLeft
ClientHeight = 100
ClientWidth = 130
TabOrder = 3
ShowText = True
ShowLevel = True
Value = 0
ValueMin = 0
ValueMax = 3000
ValueRed = 0
ValueYellow = 0
AnalogKind = akAnalog
end
object as_voc: TAnalogSensor
Left = 520
Height = 100
Top = 0
Width = 130
Align = alLeft
ClientHeight = 100
ClientWidth = 130
TabOrder = 4
ShowText = True
ShowLevel = True
Value = 0
ValueMin = 0
ValueMax = 1000
ValueRed = 0
ValueYellow = 0
AnalogKind = akAnalog
end
object as_allpollu: TAnalogSensor
Left = 650
Height = 100
Top = 0
Width = 130
Align = alLeft
ClientHeight = 100
ClientWidth = 130
TabOrder = 5
ShowText = True
ShowLevel = True
Value = 0
ValueMin = 0
ValueMax = 300
ValueRed = 0
ValueYellow = 0
AnalogKind = akAnalog
end
end
object grp_highlow: TGroupBox
Left = 0
Height = 119
Top = 120
Width = 782
Align = alTop
Caption = 'Highs and Lows'
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsScaleChilds
ChildSizing.ControlsPerLine = 6
ClientHeight = 99
ClientWidth = 778
TabOrder = 1
object grp_pm: TGroupBox
Left = 0
Height = 99
Top = 0
Width = 130
Align = alLeft
Caption = 'Particulates'
ClientHeight = 79
ClientWidth = 126
TabOrder = 0
object lbl_pmhigh: TLabel
Left = 8
Height = 15
Top = 8
Width = 60
Caption = 'lbl_pmhigh'
ParentColor = False
end
object lbl_pmlow: TLabel
Left = 8
Height = 15
Top = 40
Width = 55
Caption = 'lbl_pmlow'
ParentColor = False
end
end
object grp_tmp: TGroupBox
Left = 130
Height = 99
Top = 0
Width = 130
Align = alLeft
Caption = 'Temperature'
ClientHeight = 79
ClientWidth = 126
TabOrder = 1
object lbl_tmphigh: TLabel
Left = 8
Height = 15
Top = 8
Width = 64
Caption = 'lbl_tmphigh'
ParentColor = False
end
object lbl_tmplow: TLabel
Left = 8
Height = 15
Top = 40
Width = 59
Caption = 'lbl_tmplow'
ParentColor = False
end
end
object grp_hum: TGroupBox
Left = 260
Height = 99
Top = 0
Width = 130
Align = alLeft
Caption = 'Humidity'
ClientHeight = 79
ClientWidth = 126
TabOrder = 2
object lbl_humhigh: TLabel
Left = 8
Height = 15
Top = 8
Width = 67
Caption = 'lbl_humhigh'
ParentColor = False
end
object lbl_humlow: TLabel
Left = 8
Height = 15
Top = 40
Width = 62
Caption = 'lbl_humlow'
ParentColor = False
end
end
object grp_co2: TGroupBox
Left = 390
Height = 99
Top = 0
Width = 130
Align = alLeft
Caption = 'CO2'
ClientHeight = 79
ClientWidth = 126
TabOrder = 3
object lbl_co2high: TLabel
Left = 8
Height = 15
Top = 8
Width = 61
Caption = 'lbl_co2high'
ParentColor = False
end
object lbl_co2low: TLabel
Left = 8
Height = 15
Top = 40
Width = 56
Caption = 'lbl_co2low'
ParentColor = False
end
end
object grp_voc: TGroupBox
Left = 520
Height = 99
Top = 0
Width = 130
Align = alLeft
Caption = 'Volatile VOC'
ClientHeight = 79
ClientWidth = 126
TabOrder = 4
object lbl_vochigh: TLabel
Left = 8
Height = 15
Top = 8
Width = 61
Caption = 'lbl_vochigh'
ParentColor = False
end
object lbl_voclow: TLabel
Left = 8
Height = 15
Top = 40
Width = 56
Caption = 'lbl_voclow'
ParentColor = False
end
end
object grp_allpollu: TGroupBox
Left = 650
Height = 99
Top = 0
Width = 130
Align = alLeft
Caption = 'All Pollution'
ClientHeight = 79
ClientWidth = 126
TabOrder = 5
object lbl_allpolluhigh: TLabel
Left = 8
Height = 15
Top = 8
Width = 81
Caption = 'lbl_allpolluhigh'
ParentColor = False
end
object lbl_allpollulow: TLabel
Left = 8
Height = 15
Top = 40
Width = 76
Caption = 'lbl_allpollulow'
ParentColor = False
end
end
end
object tmr_foobot: TTimer
Enabled = False
Interval = 3600
OnTimer = tmr_foobotTimer
Left = 16
end
object MainMenu1: TMainMenu
Left = 56
Top = 8
object mnu_file: TMenuItem
Caption = '&File'
object mnu_fileExit: TMenuItem
Caption = 'E&xit'
OnClick = mnu_fileExitClick
end
end
object mnu_options: TMenuItem
Caption = '&Options'
object mnu_optionsShowHighsAndLows: TMenuItem
AutoCheck = True
Caption = 'Show Highs and Lows'
Checked = True
OnClick = mnu_optionsShowHighsAndLowsClick
end
object mnu_optionsTakeReadingNow: TMenuItem
Caption = 'Take reading now'
OnClick = mnu_optionsTakeReadingNowClick
end
object mnu_optionsSampleEvery: TMenuItem
Caption = 'Sample every...'
object mnu_SampleEvery1Hour: TMenuItem
AutoCheck = True
Caption = 'Hour (default)'
Checked = True
GroupIndex = 1
OnClick = mnu_SampleEvery1HourClick
end
object mnu_SampleEvery2Hours: TMenuItem
AutoCheck = True
Caption = '2 Hours'
OnClick = mnu_SampleEvery2HoursClick
end
object mnu_SampleEvery4Hours: TMenuItem
AutoCheck = True
Caption = '4 Hours'
OnClick = mnu_SampleEvery4HoursClick
end
object mnu_SampleEvery8Hours: TMenuItem
AutoCheck = True
Caption = '8 Hours'
OnClick = mnu_SampleEvery8HoursClick
end
object mnu_SampleEvery24Hours: TMenuItem
AutoCheck = True
Caption = '24 Hours'
GroupIndex = 1
OnClick = mnu_SampleEvery24HoursClick
end
end
object mnu_optionsSaveHighLows: TMenuItem
AutoCheck = True
Caption = 'Save/Load High-Lows to disk'
Checked = True
OnClick = mnu_optionsSaveHighLowsClick
end
end
end
end

View File

@ -0,0 +1,406 @@
unit umainform;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Sensors, Forms, Controls, Graphics, Dialogs,
ExtCtrls, StdCtrls, Menus, foobot_utility, uCryptIni, Variants, dateutils,
uconfigform;
CONST
ONEMINUTE = 60000;
ONEHOUR = ONEMINUTE * 60;
TWOHOURS = ONEHOUR * 2;
FOURHOURS = ONEHOUR * 4;
EIGHTHOURS = ONEHOUR * 8;
TWENTYFOURHOURS = ONEHOUR * 24;
type
{ Tmainform }
Tmainform = class(TForm)
as_allpollu: TAnalogSensor;
as_co2: TAnalogSensor;
as_hum: TAnalogSensor;
as_pm: TAnalogSensor;
as_tmp: TAnalogSensor;
as_voc: TAnalogSensor;
grp_pm: TGroupBox;
grp_tmp: TGroupBox;
grp_hum: TGroupBox;
grp_co2: TGroupBox;
grp_voc: TGroupBox;
grp_allpollu: TGroupBox;
grp_highlow: TGroupBox;
grp_sensorDisplay: TGroupBox;
lbl_pmhigh: TLabel;
lbl_tmphigh: TLabel;
lbl_humhigh: TLabel;
lbl_co2high: TLabel;
lbl_vochigh: TLabel;
lbl_allpolluhigh: TLabel;
lbl_pmlow: TLabel;
lbl_tmplow: TLabel;
lbl_humlow: TLabel;
lbl_co2low: TLabel;
lbl_voclow: TLabel;
lbl_allpollulow: TLabel;
MainMenu1: TMainMenu;
mnu_optionsSaveHighLows: TMenuItem;
mnu_SampleEvery24Hours: TMenuItem;
mnu_SampleEvery8Hours: TMenuItem;
mnu_SampleEvery4Hours: TMenuItem;
mnu_SampleEvery2Hours: TMenuItem;
mnu_SampleEvery1Hour: TMenuItem;
mnu_optionsSampleEvery: TMenuItem;
mnu_optionsTakeReadingNow: TMenuItem;
mnu_optionsShowHighsAndLows: TMenuItem;
mnu_options: TMenuItem;
mnu_fileExit: TMenuItem;
mnu_file: TMenuItem;
tmr_foobot: TTimer;
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure mnu_fileExitClick(Sender: TObject);
procedure mnu_optionsSaveHighLowsClick(Sender: TObject);
procedure mnu_optionsShowHighsAndLowsClick(Sender: TObject);
procedure mnu_optionsTakeReadingNowClick(Sender: TObject);
procedure mnu_SampleEvery1HourClick(Sender: TObject);
procedure mnu_SampleEvery24HoursClick(Sender: TObject);
procedure mnu_SampleEvery2HoursClick(Sender: TObject);
procedure mnu_SampleEvery4HoursClick(Sender: TObject);
procedure mnu_SampleEvery8HoursClick(Sender: TObject);
procedure tmr_foobotTimer(Sender: TObject);
private
sSecretKey, sFoobotUserName, sUUID: string;
bShowHighsAndLows: boolean;
iFudgeFactor: integer;
iSampleInterval:Integer;
procedure DisplayReadings;
procedure UpdateGuage(Sender: TAnalogSensor; SensorNumber: integer);
procedure UpdateHighLow(SensorNumber: integer);
public
INI: TCryptINIfile;
end;
var
mainform: Tmainform;
implementation
{$R *.lfm}
{ Tmainform }
procedure Tmainform.FormCreate(Sender: TObject);
begin
Caption := Application.Title;
Icon := Application.Icon;
INI := TCryptINIfile.Create(GetAppConfigFile(False));
if INI.IsVirgin then
begin
INI.WriteIdent('Gordon Bamber', '(c)2016', 'GPLV2',
'minesadorada@charcodelvalle.com', True);
end;
if not INI.VerifyIdent('41d10218d247980fc5e871b6b7844483') then
begin
ShowMessage(Application.Title +
' has been tampered wth. Please re-install from a trusted source.');
FreeAndNil(INI);
Application.Terminate;
end;
INI.SectionHashing:=FALSE;
ResetHighLows;
iFudgeFactor := 20;
ClientHeight := grp_sensorDisplay.Height + grp_highlow.Height + iFudgeFactor;
bShowHighsAndLows := True;
end;
procedure Tmainform.FormActivate(Sender: TObject);
Var sTempFoobotUserName,sTempSecretKey:String;
begin
// Allow user to enter values in INIFile
sTempFoobotUserName:=INI.ReadUnencryptedString('Config','Foobot User','unknown');
sTempSecretKey:=INI.ReadUnencryptedString('Config', 'Secret Key', 'unknown');
if ((sTempFoobotUserName <> 'unknown') and (sTempSecretKey <> 'unknown')) then
begin
INI.WriteString('Foobot', 'Foobot User', sTempFoobotUserName);
INI.DeleteKey('Config','Foobot User');
INI.WriteString('Foobot', 'Secret Key', sTempSecretKey);
INI.DeleteKey('Config','Secret Key');
end;
// Fetch Username and API_KEY
sFoobotUserName := INI.ReadString('Foobot', 'Foobot User', 'unknown');
sSecretKey := INI.ReadString('Foobot', 'Secret Key', 'unknown');
if ((sFoobotUserName <> 'unknown') and (sSecretKey <> 'unknown')) then
begin
Hide;
if FetchFoobotIdentity(sFoobotUserName, sSecretKey) then
begin
if FoobotIdentityObject.FoobotIdentityList.Count > 0 then
begin
sUUID := FoobotIdentityObject.FoobotIdentityList.Items[0].uuid;
SaveLoadHighLows:=INI.ReadBool('Foobot','SaveLoadHighLows',TRUE);
mnu_optionsSaveHighLows.Checked:=SaveLoadHighLows;
If SaveLoadHighLows then LoadHighLows;
mnu_optionsTakeReadingNow.Click;
// Switch off for testing
tmr_foobot.Interval:=ONEHOUR;
tmr_foobot.Enabled:=TRUE;
Show;
end;
end
else Close;
end
else
begin
// No valid cfg. Show config form
Hide;
Application.ProcessMessages;
configform.ShowModal;
// If user quit without data, then bail out
If NOT configform.bValid then
begin
Close;
end;
// Store encrypted Username and API_KEY
INI.WriteString('Foobot', 'Foobot User', configform.FoobotUsername);
INI.WriteString('Foobot', 'Secret Key', configform.FoobotSecretKey);
//sFoobotUserName := INI.ReadString('Foobot', 'Foobot User', 'unknown');
//sSecretKey := INI.ReadString('Foobot', 'Secret Key', 'unknown');
ShowMessage('Click OK to store settings and close the app.' + LineEnding + 'New settings are applied on resart.');
Close;
end;
end;
procedure Tmainform.FormDestroy(Sender: TObject);
begin
FreeAndNil(INI);
end;
procedure Tmainform.FormShow(Sender: TObject);
begin
end;
procedure Tmainform.mnu_fileExitClick(Sender: TObject);
begin
Close;
end;
procedure Tmainform.mnu_optionsSaveHighLowsClick(Sender: TObject);
begin
SaveLoadHighLows:=mnu_optionsSaveHighLows.Checked;
INI.WriteBool('Foobot','SaveLoadHighLows',SaveLoadHighLows);
end;
procedure Tmainform.mnu_optionsShowHighsAndLowsClick(Sender: TObject);
begin
if mnu_optionsShowHighsAndLows.Checked then
mainform.ClientHeight := grp_sensorDisplay.Height + grp_highlow.Height + iFudgeFactor
else
mainform.ClientHeight := grp_sensorDisplay.Height + iFudgeFactor;
bShowHighsAndLows := mnu_optionsShowHighsAndLows.Checked;
end;
procedure Tmainform.mnu_optionsTakeReadingNowClick(Sender: TObject);
begin
mainform.Cursor := crHourGlass;
// Only Foobot #0
if FetchFoobotData(dfLast, 0, 0, 0, 0, 0, sSecretKey) then
DisplayReadings
else
ShowMessage('Sorry - no readings available');
mainform.Cursor := crDefault;
end;
procedure Tmainform.mnu_SampleEvery1HourClick(Sender: TObject);
begin
tmr_foobot.Enabled:=FALSE;
tmr_foobot.Interval:=ONEHOUR;
tmr_foobot.Enabled:=TRUE;
end;
procedure Tmainform.mnu_SampleEvery24HoursClick(Sender: TObject);
begin
tmr_foobot.Enabled:=FALSE;
tmr_foobot.Interval:=TWENTYFOURHOURS;
tmr_foobot.Enabled:=TRUE;
end;
procedure Tmainform.mnu_SampleEvery2HoursClick(Sender: TObject);
begin
tmr_foobot.Enabled:=FALSE;
tmr_foobot.Interval:=TWOHOURS;
tmr_foobot.Enabled:=TRUE;
end;
procedure Tmainform.mnu_SampleEvery4HoursClick(Sender: TObject);
begin
tmr_foobot.Enabled:=FALSE;
tmr_foobot.Interval:=FOURHOURS;
tmr_foobot.Enabled:=TRUE;
end;
procedure Tmainform.mnu_SampleEvery8HoursClick(Sender: TObject);
begin
tmr_foobot.Enabled:=FALSE;
tmr_foobot.Interval:=EIGHTHOURS;
tmr_foobot.Enabled:=TRUE;
end;
procedure Tmainform.tmr_foobotTimer(Sender: TObject);
begin
if FetchFoobotData(dfLast, 0, 0, 0, 0, 0, sSecretKey) then
DisplayReadings;
end;
procedure Tmainform.UpdateHighLow(SensorNumber: integer);
begin
case SensorNumber of
1:
begin
lbl_pmhigh.Caption := Format(
'High: %f %s', [double(FoobotDataHighs[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) + LineEnding + 'on ' +
FormatDateTime('dd/mm tt', TDateTime(FoobotDataHighTimes[SensorNumber]));
lbl_pmLow.Caption := Format(
'Low: %f %s', [double(FoobotDataLows[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) +
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
2:
begin
lbl_tmphigh.Caption := Format(
'High: %f %s', [double(FoobotDataHighs[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) + LineEnding + 'on ' +
FormatDateTime('dd/mm tt', TDateTime(FoobotDataHighTimes[SensorNumber]));
lbl_tmpLow.Caption := Format(
'Low: %f %s', [double(FoobotDataLows[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) +
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
3:
begin
lbl_humhigh.Caption := Format(
'High: %f %s', [double(FoobotDataHighs[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) + LineEnding + 'on ' +
FormatDateTime('dd/mm tt', TDateTime(FoobotDataHighTimes[SensorNumber]));
lbl_humLow.Caption := Format(
'Low: %f %s', [double(FoobotDataLows[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) +
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
4:
begin
lbl_co2high.Caption := Format(
'High: %f %s', [double(FoobotDataHighs[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) + LineEnding + 'on ' +
FormatDateTime('dd/mm tt', TDateTime(FoobotDataHighTimes[SensorNumber]));
lbl_co2Low.Caption := Format(
'Low: %f %s', [double(FoobotDataLows[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) +
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
5:
begin
lbl_vochigh.Caption := Format(
'High: %f %s', [double(FoobotDataHighs[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) + LineEnding + 'on ' +
FormatDateTime('dd/mm tt', TDateTime(FoobotDataHighTimes[SensorNumber]));
lbl_vocLow.Caption := Format(
'Low: %f %s', [double(FoobotDataLows[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) +
LineEnding + 'on ' + FormatDateTime('dd/mm tt', TDateTime(
FoobotDataLowTimes[SensorNumber]));
end;
6:
begin
lbl_allpolluhigh.Caption :=
Format('High: %f %s', [double(FoobotDataHighs[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) + LineEnding + 'on ' +
FormatDateTime('dd/mm tt', TDateTime(FoobotDataHighTimes[SensorNumber]));
lbl_allpollulow.Caption :=
Format('Low: %f %s', [double(FoobotDataLows[SensorNumber]),
FoobotDataObject.Units[SensorNumber]]) + LineEnding + 'on ' +
FormatDateTime('dd/mm tt', TDateTime(FoobotDataLowTimes[SensorNumber]));
end;
end;
end;
procedure Tmainform.UpdateGuage(Sender: TAnalogSensor; SensorNumber: integer);
begin
with Sender do
begin
case SensorNumber of
1:
begin
Value := FoobotData_pm[0];
Caption := Format('PM (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
2:
begin
Value := FoobotData_tmp[0];
Caption := Format('Temp (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
3:
begin
Value := FoobotData_hum[0];
Caption := Format('Hum. (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
4:
begin
Value := FoobotData_co2[0];
Caption := Format('CO2 (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
5:
begin
Value := FoobotData_voc[0];
Caption := Format('VOC (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
6:
begin
Value := FoobotData_allpollu[0];
Caption := Format('All (%s): ', [FoobotDataObject.Units[SensorNumber]]);
end;
end;
if Value > ValueMax then
ValueMax := Value;
ValueYellow := ValueMax;
if Value > ValueRed then
ValueRed := Value;
end;
end;
procedure Tmainform.DisplayReadings;
var
iCount: integer;
begin
if FoobotDataObjectToArrays = True then
begin
mainform.Caption := Format('Foobot "%s" - ',
[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);
if bShowHighsAndLows then
for iCount := 1 to 6 do
UpdateHighLow(iCount);
end;
end;
end.