This commit is contained in:
Amirul Shafiq 2026-03-19 11:53:15 +08:00
commit 080a9785ed
282 changed files with 218271 additions and 0 deletions

484
.gitignore vendored Normal file
View File

@ -0,0 +1,484 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from `dotnet new gitignore`
# dotenv files
.env
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET
project.lock.json
project.fragment.lock.json
artifacts/
# Tye
.tye/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
.idea/
##
## Visual studio for Mac
##
# globs
Makefile.in
*.userprefs
*.usertasks
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.tar.gz
tarballs/
test-results/
# Mac bundle stuff
*.dmg
*.app
# content below from: https://github.com/github/gitignore/blob/main/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# content below from: https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# Vim temporary swap files
*.swp

31
PSTW.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36930.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Udara", "Udara\Udara.csproj", "{9E992754-F4BE-49BB-A4F6-747CDBDB11B1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UdaraWindows", "UdaraWindows\UdaraWindows.csproj", "{D4047220-220B-45B3-A137-C2611774473A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9E992754-F4BE-49BB-A4F6-747CDBDB11B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E992754-F4BE-49BB-A4F6-747CDBDB11B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E992754-F4BE-49BB-A4F6-747CDBDB11B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9E992754-F4BE-49BB-A4F6-747CDBDB11B1}.Release|Any CPU.Build.0 = Release|Any CPU
{D4047220-220B-45B3-A137-C2611774473A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4047220-220B-45B3-A137-C2611774473A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4047220-220B-45B3-A137-C2611774473A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4047220-220B-45B3-A137-C2611774473A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6F63CE08-E9F9-4DB5-836F-B97740D42AA9}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,7 @@
namespace Udara.Common.Feature.Csv;
public sealed class CsvParseResult
{
public string[] Header { get; init; } = Array.Empty<string>();
public IReadOnlyList<string[]> Rows { get; init; } = Array.Empty<string[]>();
}

View File

@ -0,0 +1,43 @@
namespace Udara.Common.Feature.Csv;
public sealed class CsvParser : ICsvParser
{
public IReadOnlyList<string[]> ParseRaw(string csvContent)
{
if (string.IsNullOrWhiteSpace(csvContent))
return Array.Empty<string[]>();
var lines = csvContent
.Split('\n', StringSplitOptions.RemoveEmptyEntries);
var rows = new List<string[]>(lines.Length);
foreach (var line in lines)
{
var columns = line
.TrimEnd('\r')
.Split(',', StringSplitOptions.None);
rows.Add(columns);
}
return rows;
}
public CsvParseResult Parse(string csvContent)
{
var raw = ParseRaw(csvContent);
if (raw.Count == 0)
return new CsvParseResult();
var header = raw[0];
var rows = raw.Skip(1).ToList();
return new CsvParseResult
{
Header = header,
Rows = rows
};
}
}

View File

@ -0,0 +1,7 @@
namespace Udara.Common.Feature.Csv;
public interface ICsvParser
{
IReadOnlyList<string[]> ParseRaw(string csvContent);
CsvParseResult Parse(string csvContent);
}

View File

@ -0,0 +1,6 @@
namespace Udara.Common.Feature.Telegram;
public interface ITelegramSettingsProvider
{
Task<TelegramApiSettingsModel> GetSettingsAsync(CancellationToken token = default);
}

View File

@ -0,0 +1,11 @@
namespace Udara.Common.Feature.Telegram;
public sealed class TelegramApiSettingsModel
{
public string Protocol { get; set; } = null!;
public string Host { get; set; } = null!;
public string Mode { get; set; } = null!;
public string Token { get; set; } = null!;
public string Method { get; set; } = null!;
public string TargetChatId { get; set; } = null!;
}

View File

@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Connections;
using Microsoft.EntityFrameworkCore;
using Udara.Database.App;
namespace Udara.Common.Feature.Telegram;
public sealed class TelegramSettingsProvider : ITelegramSettingsProvider
{
private readonly IServiceScopeFactory _scopeFactory;
public TelegramSettingsProvider(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public async Task<TelegramApiSettingsModel> GetSettingsAsync(CancellationToken token = default)
{
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var telegramConfigDict = (await db.AppConfigs
.Where(x => x.Category == "Telegram")
.ToListAsync(token))
.ToDictionary(x => x.ConfigKey, x => x.ConfigValue);
var model = new TelegramApiSettingsModel
{
Protocol = telegramConfigDict["TelegramApiProtocol"],
Host = telegramConfigDict["TelegramApiHost"],
Mode = telegramConfigDict["TelegramApiBotIdentifier"],
Method = telegramConfigDict["TelegramApiSendMessageMethod"],
Token = telegramConfigDict["TelegramApiBotToken"],
TargetChatId = telegramConfigDict["TelegramApiTargetChatId"]
};
return model;
}
}

View File

@ -0,0 +1,6 @@
namespace Udara.Common.Feature.Time;
public interface IMinuteAlignment
{
Task SecondsUntilNextMinuteAsync(int inputSeconds, CancellationToken token);
}

View File

@ -0,0 +1,14 @@
namespace Udara.Common.Feature.Time;
public class MinuteAlignment : IMinuteAlignment
{
public async Task SecondsUntilNextMinuteAsync(int inputSeconds, CancellationToken token)
{
var nowTime = DateTime.Now;
DateTime baseTime = new(nowTime.Year, nowTime.Month, nowTime.Day, nowTime.Hour, nowTime.Minute, 0, 0);
DateTime nextTime = baseTime.AddSeconds(
Math.Ceiling((nowTime - baseTime).TotalSeconds / inputSeconds) * inputSeconds);
TimeSpan delayTime = nextTime - nowTime;
await Task.Delay(delayTime, token);
}
}

View File

@ -0,0 +1,41 @@
using Microsoft.EntityFrameworkCore;
using Udara.Database.App.Model;
namespace Udara.Database.App;
public class AppDbContext : DbContext
{
public DbSet<AppConfigsModel> AppConfigs => Set<AppConfigsModel>();
public DbSet<DeviceListModel> DeviceList => Set<DeviceListModel>();
public DbSet<DeviceParametersModel> DeviceParameters => Set<DeviceParametersModel>();
public DbSet<DeviceFlagsModel> DeviceFlags => Set<DeviceFlagsModel>();
public DbSet<DeviceModbusModel> DeviceModbus => Set<DeviceModbusModel>();
public DbSet<DeviceSerialModel> DeviceSerial => Set<DeviceSerialModel>();
public DbSet<DeviceSqlServerModel> DeviceSqlServer => Set<DeviceSqlServerModel>();
public DbSet<DeviceDatafileModel> DeviceDatafile => Set<DeviceDatafileModel>();
public DbSet<FtpListModel> FtpList => Set<FtpListModel>();
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder model)
{
model.Entity<AppConfigsModel>(entity =>
{
entity.ToTable("AppConfigs");
entity.HasKey(x => x.ConfigKey);
entity.Property(x => x.ConfigKey).IsRequired();
entity.Property(x => x.ConfigValue).IsRequired();
entity.Property(x => x.ValueType).IsRequired();
entity.Property(x => x.UpdatedAt).ValueGeneratedOnAddOrUpdate();
});
}
}

View File

@ -0,0 +1,10 @@
namespace Udara.Database.App.Model;
public sealed class AppConfigsModel
{
public string ConfigKey { get; set; } = default!;
public string ConfigValue { get; set; } = default!;
public string ValueType { get; set; } = default!;
public string Category { get; set; } = default!;
public DateTime UpdatedAt { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Udara.Database.App.Model;
public class DeviceCoils
{
//public int Id { get; set; }
//public int DeviceId { get; set; }
//public int Coil { get; set; }
//public string Name { get; set; } = string.Empty;
}

View File

@ -0,0 +1,12 @@
namespace Udara.Database.App.Model;
public class DeviceDatafileModel
{
public int Id { get; set; }
public int DeviceId { get; set; }
public string ProcessName { get; set; } = string.Empty;
public string TargetDir { get; set; } = string.Empty;
public string FilePattern { get; set; } = string.Empty;
public string FileExtension { get; set; } = string.Empty;
}

View File

@ -0,0 +1,9 @@
namespace Udara.Database.App.Model;
public class DeviceFlagsModel
{
public int Id { get; set; }
public int DeviceId { get; set; }
public int FlagId { get; set; }
public string FlagName { get; set; } = string.Empty;
}

View File

@ -0,0 +1,10 @@
namespace Udara.Database.App.Model;
public class DeviceListModel
{
public int Id { get; set; }
public string Code { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Mode { get; set; } = string.Empty;
public int IsEnabled { get; set; }
}

View File

@ -0,0 +1,25 @@
namespace Udara.Database.App.Model;
public class DeviceModbusModel
{
public int Id { get; set; }
public int DeviceId { get; set; }
public string Mode { get; set; } = string.Empty;
// TCP
public string? Host { get; set; }
public int? TcpPort { get; set; }
// RTU
public string? PortName { get; set; }
public int? BaudRate { get; set; }
public int? DataBits { get; set; }
public int? StopBits { get; set; }
public string? Parity { get; set; }
// Common
public int? SlaveAddress { get; set; }
public int? Reference { get; set; }
public int? Count { get; set; }
public string? DataType { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Udara.Database.App.Model;
public class DeviceParametersModel
{
public int Id { get; set; }
public int DeviceId { get; set; }
public int ParameterId { get; set; }
public string ParameterName { get; set; } = string.Empty;
}

View File

@ -0,0 +1,9 @@
namespace Udara.Database.App.Model;
public class DeviceRegisters
{
//public int Id { get; set; }
//public int DeviceId { get; set; }
//public int Register { get; set; }
//public string Name { get; set; } = string.Empty;
}

View File

@ -0,0 +1,17 @@
namespace Udara.Database.App.Model;
public class DeviceSerialModel
{
public int Id { get; set; }
public int DeviceId { get; set; }
public string PortName { get; set; } = string.Empty;
public int BaudRate { get; set; }
public int DataBits { get; set; }
public string Parity { get; set; } = string.Empty;
public int StopBits { get; set; }
public string FlowControl { get; set; } = string.Empty;
public string Encoding { get; set; } = string.Empty;
public string NewLine { get; set; } = string.Empty;
public int ReadTimeout { get; set; }
public int WriteTimeout { get; set; }
}

View File

@ -0,0 +1,14 @@
namespace Udara.Database.App.Model;
public class DeviceSqlServerModel
{
public int Id { get; set; }
public int DeviceId { get; set; }
public string Host { get; set; } = string.Empty;
public string DatabaseName { get; set; } = string.Empty;
public string? PreferedDatabaseName { get; set; }
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string ConnectionOptions { get; set; } = string.Empty;
public string Query { get; set; } = string.Empty;
}

View File

@ -0,0 +1,16 @@
namespace Udara.Database.App.Model;
public sealed class FtpListModel
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Host { get; set; } = string.Empty;
public int Port { get; set; }
public string Protocol { get; set; } = string.Empty;
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public bool IsPassive { get; set; }
public string? RemoteDirectory { get; set; }
public string? ExtraJson { get; set; }
public bool IsEnabled { get; set; }
}

View File

@ -0,0 +1,150 @@
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
CREATE TABLE AppConfigs (
ConfigKey TEXT PRIMARY KEY,
ConfigValue TEXT NOT NULL,
ValueType TEXT NOT NULL, -- string, int, bool, json, etc.
UpdatedAt TEXT NOT NULL DEFAULT (strftime('%Y-%m-%d %H:%M:%S', 'now', 'localtime'))
);
CREATE TRIGGER AppConfigs_UpdateTimestamp
AFTER UPDATE ON AppConfigs
FOR EACH ROW
BEGIN
UPDATE AppConfigs
SET UpdatedAt = strftime('%Y-%m-%d %H:%M:%S', 'now', 'localtime')
WHERE ConfigKey = NEW.ConfigKey;
END;
CREATE TRIGGER AppConfigs_InsertTimestamp
AFTER INSERT ON AppConfigs
FOR EACH ROW
BEGIN
UPDATE AppConfigs
SET UpdatedAt = strftime('%Y-%m-%d %H:%M:%S', 'now', 'localtime')
WHERE ConfigKey = NEW.ConfigKey;
END;
-- ----------------------------------------------------------------------
CREATE TABLE "DeviceList" (
"Id" INTEGER PRIMARY KEY AUTOINCREMENT,
"Code" TEXT NOT NULL,
"Name" TEXT NOT NULL,
"Mode" TEXT NOT NULL,
"IsEnabled" INTEGER
)
CREATE TABLE FtpList (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Host TEXT NOT NULL,
Port INTEGER NOT NULL,
Protocol TEXT NOT NULL,
Username TEXT NOT NULL,
Password TEXT NOT NULL,
IsPassive INTEGER NOT NULL,
RemoteDirectory TEXT NULL,
ExtraJson TEXT NULL,
IsEnabled INTEGER NOT NULL
)
-- ----------------------------------------------------------------------
CREATE TABLE DeviceFlags (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
DeviceId INTEGER NOT NULL,
FlagId INTEGER NOT NULL,
FlagName TEXT NOT NULL,
FOREIGN KEY(DeviceId) REFERENCES "DeviceList"(Id)
)
CREATE TABLE "DeviceParameters" (
"Id" INTEGER PRIMARY KEY AUTOINCREMENT,
"DeviceId" INTEGER NOT NULL,
"ParameterId" INTEGER NOT NULL,
"ParameterName" TEXT NOT NULL,
FOREIGN KEY("DeviceId") REFERENCES "DeviceList"("Id")
)
-- ----------------------------------------------------------------------
CREATE TABLE "DeviceModbus" (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
DeviceId INTEGER NOT NULL,
Mode TEXT NOT NULL,
-- TCP
Host TEXT,
TcpPort INTEGER,
-- RTU
PortName TEXT,
BaudRate INTEGER,
DataBits INTEGER,
StopBits INTEGER,
Parity TEXT,
-- Common
SlaveAddress INTEGER,
Reference INTEGER,
Count INTEGER,
DataType TEXT
)
CREATE TABLE "DeviceSerial" (
"Id" INTEGER PRIMARY KEY AUTOINCREMENT,
"DeviceId" INTEGER NOT NULL,
"PortName" TEXT NOT NULL,
"BaudRate" INTEGER NOT NULL,
"DataBits" INTEGER NOT NULL,
"Parity" TEXT NOT NULL,
"StopBits" INTEGER NOT NULL,
"FlowControl" TEXT NOT NULL,
"Encoding" TEXT NOT NULL,
"NewLine" TEXT NOT NULL,
"ReadTimeout" INTEGER NOT NULL,
"WriteTimeout" INTEGER NOT NULL
)
CREATE TABLE DeviceSqlServer (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
DeviceId INTEGER NOT NULL,
Host TEXT NOT NULL,
DatabaseName TEXT NOT NULL,
PreferedDatabaseName TEXT,
Username TEXT NOT NULL,
Password TEXT NOT NULL,
ConnectionOptions TEXT NOT NULL,
Query TEXT NOT NULL
)
CREATE TABLE "DeviceDatafile" (
"Id" INTEGER PRIMARY KEY AUTOINCREMENT,
"DeviceId" INTEGER NOT NULL,
"ProcessName" TEXT NOT NULL,
"FilePattern" TEXT NOT NULL,
"FileExtension" TEXT NOT NULL,
FOREIGN KEY("DeviceId") REFERENCES "DeviceList"("Id")
)
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
CREATE TABLE DeviceCoils (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
DeviceId INTEGER NOT NULL,
Coil INTEGER NOT NULL,
Name TEXT NOT NULL,
FOREIGN KEY(DeviceId) REFERENCES "DeviceList"(Id)
)
CREATE TABLE DeviceRegisters (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
DeviceId INTEGER NOT NULL,
Register INTEGER NOT NULL,
Name TEXT NOT NULL,
FOREIGN KEY(DeviceId) REFERENCES "DeviceList"(Id)
)

View File

@ -0,0 +1,32 @@
using Microsoft.EntityFrameworkCore;
using Udara.Database.Data.Model;
namespace Udara.Database.Data;
public class DataDbContext : DbContext
{
public DataDbContext(DbContextOptions<DataDbContext> options)
: base(options)
{
}
public DbSet<RawDataModel> RawData => Set<RawDataModel>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<RawDataModel>(entity =>
{
entity.ToTable("RawData");
entity.HasKey(x => x.Id);
entity.Property(x => x.Timestamp)
.IsRequired();
entity.Property(x => x.Log)
.IsRequired();
});
}
}

View File

@ -0,0 +1,8 @@
namespace Udara.Database.Data.Model;
public class RawDataModel
{
public int Id { get; set; }
public DateTime Timestamp { get; set; }
public string Log { get; set; } = string.Empty;
}

View File

@ -0,0 +1,5 @@
CREATE TABLE "RawData" (
"Id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"Timestamp" TEXT NOT NULL,
"Log" TEXT NOT NULL
);

BIN
Udara/Database/app.db Normal file

Binary file not shown.

View File

@ -0,0 +1,357 @@
Record Date
Station
teom_teom_a_1-hr_mass_conc
teom_teom_b_1-hr_mass_conc
nox_no
nox_no2
nox_nox
so2_so2
co_co
o3_o3
ozonePrecursor_n-Hexane
ozonePrecursor_Benzene
ozonePrecursor_2_2_4-Trimethylpentane
ozonePrecursor_n-Heptane
ozonePrecursor_Toluene
ozonePrecursor_n-Octane
ozonePrecursor_Ethylbenzene
ozonePrecursor_m_p-Xylene
ozonePrecursor_Styrene
ozonePrecursor_o-Xylene
ozonePrecursor_1_3_5-Trimethylbenzene
ozonePrecursor_1_2_4-Trimethylbenzene
ozonePrecursor_1_2_3-Trimethylbenzene
ozonePrecursor_Ethane
ozonePrecursor_Ethene
ozonePrecursor_Propane
ozonePrecursor_Propene
ozonePrecursor_i-Butane
ozonePrecursor_n-Butane
ozonePrecursor_Acetylene
ozonePrecursor_trans-2-Butene
ozonePrecursor_1-Butene
ozonePrecursor_cis-2-Butene
ozonePrecursor_i-Pentane
ozonePrecursor_n-Pentane
ozonePrecursor_1_3-Butadiene
ozonePrecursor_trans-2-Pentene
ozonePrecursor_1-Pentene
ozonePrecursor_cis-2-Pentene
ozonePrecursor_2-Methylpentane
ozonePrecursor_n-Hexane(VOC)
ozonePrecursor_Isoprene
aio_wind_speed
aio_wind_direction
aio_ambient_temperature
aio_relative_humidity
aio_solar_radiation
nox_no_daily_Qccheck_zero_actual
nox_no_daily_Qccheck_zero_target
nox_no_daily_Qccheck_zero_drift
nox_no_daily_Qccheck_span_actual
nox_no_daily_Qccheck_span_target
nox_no_daily_Qccheck_span_drift
nox_no2_daily_Qccheck_zero_target
nox_no2_daily_Qccheck_zero_actual
nox_no2_daily_Qccheck_zero_drift
nox_no2_daily_Qccheck_span_actual
nox_no2_daily_Qccheck_span_target
nox_no2_daily_Qccheck_span_drift
nox_nox_daily_Qccheck_zero_actual
nox_nox_daily_Qccheck_zero_target
nox_nox_daily_Qccheck_zero_drift
nox_nox_daily_Qccheck_span_actual
nox_nox_daily_Qccheck_span_target
nox_nox_daily_Qccheck_span_drift
so2_so2_daily_Qccheck_zero_actual
so2_so2_daily_Qccheck_zero_target
so2_so2_daily_Qccheck_zero_drift
so2_so2_daily_Qccheck_span_actual
so2_so2_daily_Qccheck_span_target
so2_so2_daily_Qccheck_span_drift
co_co_daily_Qccheck_zero_actual
co_co_daily_Qccheck_zero_target
co_co_daily_Qccheck_zero_drift
co_co_daily_Qccheck_span_actual
co_co_daily_Qccheck_span_target
co_co_daily_Qccheck_span_drift
o3_o3_daily_Qccheck_zero_actual
o3_o3_daily_Qccheck_zero_target
o3_o3_daily_Qccheck_zero_drift
o3_o3_daily_Qccheck_span_actual
o3_o3_daily_Qccheck_span_target
o3_o3_daily_Qccheck_span_drift
ozonePrecursor_n-Hexane_daily_Qccheck_span_drift
ozonePrecursor_Benzene_daily_Qccheck_span_drift
ozonePrecursor_2_2_4-Trimethylpentane_daily_Qccheck_span_drift
ozonePrecursor_n-Heptane_daily_Qccheck_span_drift
ozonePrecursor_Toluene_daily_Qccheck_span_drift
ozonePrecursor_n-Octane_daily_Qccheck_span_drift
ozonePrecursor_Ethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_m_p-Xylene_daily_Qccheck_span_drift
ozonePrecursor_Styrene_daily_Qccheck_span_drift
ozonePrecursor_o-Xylene_daily_Qccheck_span_drift
ozonePrecursor_1_3_5-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_1_2_4-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_1_2_3-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_Ethane_daily_Qccheck_span_drift
ozonePrecursor_Ethene_daily_Qccheck_span_drift
ozonePrecursor_Propane_daily_Qccheck_span_drift
ozonePrecursor_Propene_daily_Qccheck_span_drift
ozonePrecursor_i-Butane_daily_Qccheck_span_drift
ozonePrecursor_n-Butane_daily_Qccheck_span_drift
ozonePrecursor_Acetylene_daily_Qccheck_span_drift
ozonePrecursor_trans-2-Butene_daily_Qccheck_span_drift
ozonePrecursor_1-Butene_daily_Qccheck_span_drift
ozonePrecursor_cis-2-Butene_daily_Qccheck_span_drift
ozonePrecursor_i-Pentane_daily_Qccheck_span_drift
ozonePrecursor_n-Pentane_daily_Qccheck_span_drift
ozonePrecursor_1_3-Butadiene_daily_Qccheck_span_drift
ozonePrecursor_trans-2-Pentene_daily_Qccheck_span_drift
ozonePrecursor_cis-2-Pentene_daily_Qccheck_span_drift
ozonePrecursor_2-Methylpentane_daily_Qccheck_span_drift
ozonePrecursor_n-Hexane(VOC)_daily_Qccheck_span_drift
ozonePrecursor_Isoprene_daily_Qccheck_span_drift
nox_no_single_cal_zero_actual
nox_no_single_cal_zero_target
nox_no_single_cal_zero_drift
nox_no_single_cal_span_actual
nox_no_single_cal_span_target
nox_no_single_cal_span_drift
nox_no2_single_cal_zero_actual
nox_no2_single_cal_zero_target
nox_no2_single_cal_zero_drift
nox_no2_single_cal_span_actual
nox_no2_single_cal_span_target
nox_no2_single_cal_span_drift
nox_nox_single_cal_zero_actual
nox_nox_single_cal_zero_target
nox_nox_single_cal_zero_drift
nox_nox_single_cal_span_actual
nox_nox_single_cal_span_target
nox_nox_single_cal_span_drift
so2_so2_single_cal_zero_actual
so2_so2_single_cal_zero_target
so2_so2_single_cal_zero_drift
so2_so2_single_cal_span_actual
so2_so2_single_cal_span_target
so2_so2_single_cal_span_drift
co_co_single_cal_zero_actual
co_co_single_cal_zero_target
co_co_single_cal_zero_drift
co_co_single_cal_span_actual
co_co_single_cal_span_target
co_co_single_cal_span_drift
o3_o3_single_cal_zero_actual
o3_o3_single_cal_zero_target
o3_o3_single_cal_zero_drift
o3_o3_single_cal_span_actual
o3_o3_single_cal_span_target
o3_o3_single_cal_span_drift
nox_no_multi_cal_zero_actual
nox_no_multi_cal_zero_target
nox_no_multi_cal_zero_drift
nox_no_multi_cal_span1_actual
nox_no_multi_cal_span1_target
nox_no_multi_cal_span1_drift
nox_no_multi_cal_span2_actual
nox_no_multi_cal_span2_target
nox_no_multi_cal_span2_drift
nox_no_multi_cal_span3_actual
nox_no_multi_cal_span3_target
nox_no_multi_cal_span3_drift
nox_no_multi_cal_span4_actual
nox_no_multi_cal_span4_target
nox_no_multi_cal_span4_drift
nox_no2_multi_cal_zero_actual
nox_no2_multi_cal_zero_target
nox_no2_multi_cal_zero_drift
nox_no2_multi_cal_span1_actual
nox_no2_multi_cal_span1_target
nox_no2_multi_cal_span1_drift
nox_no2_multi_cal_span2_actual
nox_no2_multi_cal_span2_target
nox_no2_multi_cal_span2_drift
nox_no2_multi_cal_span3_actual
nox_no2_multi_cal_span3_target
nox_no2_multi_cal_span3_drift
nox_no2_multi_cal_span4_actual
nox_no2_multi_cal_span4_target
nox_no2_multi_cal_span4_drift
nox_nox_multi_cal_zero_actual
nox_nox_multi_cal_zero_target
nox_nox_multi_cal_zero_drift
nox_nox_multi_cal_span1_actual
nox_nox_multi_cal_span1_target
nox_nox_multi_cal_span1_drift
nox_nox_multi_cal_span2_actual
nox_nox_multi_cal_span2_target
nox_nox_multi_cal_span2_drift
nox_nox_multi_cal_span3_actual
nox_nox_multi_cal_span3_target
nox_nox_multi_cal_span3_drift
nox_nox_multi_cal_span4_actual
nox_nox_multi_cal_span4_target
nox_nox_multi_cal_span4_drift
so2_so2_multi_cal_zero_actual
so2_so2_multi_cal_zero_target
so2_so2_multi_cal_zero_drift
so2_so2_multi_cal_span1_actual
so2_so2_multi_cal_span1_target
so2_so2_multi_cal_span1_drift
so2_so2_multi_cal_span2_actual
so2_so2_multi_cal_span2_target
so2_so2_multi_cal_span2_drift
so2_so2_multi_cal_span3_actual
so2_so2_multi_cal_span3_target
so2_so2_multi_cal_span3_drift
so2_so2_multi_cal_span4_actual
so2_so2_multi_cal_span4_target
so2_so2_multi_cal_span4_drift
co_co_multi_cal_zero_actual
co_co_multi_cal_zero_target
co_co_multi_cal_zero_drift
co_co_multi_cal_span1_actual
co_co_multi_cal_span1_target
co_co_multi_cal_span1_drift
co_co_multi_cal_span2_actual
co_co_multi_cal_span2_target
co_co_multi_cal_span2_drift
co_co_multi_cal_span3_actual
co_co_multi_cal_span3_target
co_co_multi_cal_span3_drift
co_co_multi_cal_span4_actual
co_co_multi_cal_span4_target
co_co_multi_cal_span4_drift
o3_o3_multi_cal_zero_actual
o3_o3_multi_cal_zero_target
o3_o3_multi_cal_zero_drift
o3_o3_multi_cal_span1_actual
o3_o3_multi_cal_span1_target
o3_o3_multi_cal_span1_drift
o3_o3_multi_cal_span2_actual
o3_o3_multi_cal_span2_target
o3_o3_multi_cal_span2_drift
o3_o3_multi_cal_span3_actual
o3_o3_multi_cal_span3_target
o3_o3_multi_cal_span3_drift
o3_o3_multi_cal_span4_actual
o3_o3_multi_cal_span4_target
o3_o3_multi_cal_span4_drift
ozonePrecursor_n-Hexane_single_cal_span_actual
ozonePrecursor_n-Hexane_single_cal_span_target
ozonePrecursor_n-Hexane_single_cal_span_drift
ozonePrecursor_Benzene_single_cal_span_actual
ozonePrecursor_Benzene_single_cal_span_target
ozonePrecursor_Benzene_single_cal_span_drift
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_actual
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_target
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_drift
ozonePrecursor_n-Heptane_single_cal_span_actual
ozonePrecursor_n-Heptane_single_cal_span_target
ozonePrecursor_n-Heptane_single_cal_span_drift
ozonePrecursor_Toluene_single_cal_span_actual
ozonePrecursor_Toluene_single_cal_span_target
ozonePrecursor_Toluene_single_cal_span_drift
ozonePrecursor_n-Octane_single_cal_span_actual
ozonePrecursor_n-Octane_single_cal_span_target
ozonePrecursor_n-Octane_single_cal_span_drift
ozonePrecursor_Ethylbenzene_single_cal_span_actual
ozonePrecursor_Ethylbenzene_single_cal_span_target
ozonePrecursor_Ethylbenzene_single_cal_span_drift
ozonePrecursor_m_p-Xylene_single_cal_span_actual
ozonePrecursor_m_p-Xylene_single_cal_span_target
ozonePrecursor_m_p-Xylene_single_cal_span_drift
ozonePrecursor_Styrene_single_cal_span_actual
ozonePrecursor_Styrene_single_cal_span_target
ozonePrecursor_Styrene_single_cal_span_drift
ozonePrecursor_o-Xylene_single_cal_span_actual
ozonePrecursor_o-Xylene_single_cal_span_target
ozonePrecursor_o-Xylene_single_cal_span_drift
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_Ethane_single_cal_span_actual
ozonePrecursor_Ethane_single_cal_span_target
ozonePrecursor_Ethane_single_cal_span_drift
ozonePrecursor_Ethene_single_cal_span_actual
ozonePrecursor_Ethene_single_cal_span_target
ozonePrecursor_Ethene_single_cal_span_drift
ozonePrecursor_Propane_single_cal_span_actual
ozonePrecursor_Propane_single_cal_span_target
ozonePrecursor_Propane_single_cal_span_drift
ozonePrecursor_Propene_single_cal_span_actual
ozonePrecursor_Propene_single_cal_span_target
ozonePrecursor_Propene_single_cal_span_drift
ozonePrecursor_i-Butane_single_cal_span_actual
ozonePrecursor_i-Butane_single_cal_span_target
ozonePrecursor_i-Butane_single_cal_span_drift
ozonePrecursor_n-Butane_single_cal_span_actual
ozonePrecursor_n-Butane_single_cal_span_target
ozonePrecursor_n-Butane_single_cal_span_drift
ozonePrecursor_Acetylene_single_cal_span_actual
ozonePrecursor_Acetylene_single_cal_span_target
ozonePrecursor_Acetylene_single_cal_span_drift
ozonePrecursor_trans-2-Butene_single_cal_span_actual
ozonePrecursor_trans-2-Butene_single_cal_span_target
ozonePrecursor_trans-2-Butene_single_cal_span_drift
ozonePrecursor_1-Butene_single_cal_span_actual
ozonePrecursor_1-Butene_single_cal_span_target
ozonePrecursor_1-Butene_single_cal_span_drift
ozonePrecursor_cis-2-Butene_single_cal_span_actual
ozonePrecursor_cis-2-Butene_single_cal_span_target
ozonePrecursor_cis-2-Butene_single_cal_span_drift
ozonePrecursor_i-Pentane_single_cal_span_actual
ozonePrecursor_i-Pentane_single_cal_span_target
ozonePrecursor_i-Pentane_single_cal_span_drift
ozonePrecursor_n-Pentane_single_cal_span_actual
ozonePrecursor_n-Pentane_single_cal_span_target
ozonePrecursor_n-Pentane_single_cal_span_drift
ozonePrecursor_1_3-Butadiene_single_cal_span_actual
ozonePrecursor_1_3-Butadiene_single_cal_span_target
ozonePrecursor_1_3-Butadiene_single_cal_span_drift
ozonePrecursor_trans-2-Pentene_single_cal_span_actual
ozonePrecursor_trans-2-Pentene_single_cal_span_target
ozonePrecursor_trans-2-Pentene_single_cal_span_drift
ozonePrecursor_1-Pentene_single_cal_span_actual
ozonePrecursor_1-Pentene_single_cal_span_target
ozonePrecursor_1-Pentene_single_cal_span_drift
ozonePrecursor_cis-2-Pentene_single_cal_span_actual
ozonePrecursor_cis-2-Pentene_single_cal_span_target
ozonePrecursor_cis-2-Pentene_single_cal_span_drift
ozonePrecursor_2-Methylpentane_single_cal_span_actual
ozonePrecursor_2-Methylpentane_single_cal_span_target
ozonePrecursor_2-Methylpentane_single_cal_span_drift
ozonePrecursor_n-Hexane(VOC)_single_cal_span_actual
ozonePrecursor_n-Hexane(VOC)_single_cal_span_target
ozonePrecursor_n-Hexane(VOC)_single_cal_span_drift
ozonePrecursor_Isoprene_single_cal_span_actual
ozonePrecursor_Isoprene_single_cal_span_target
ozonePrecursor_Isoprene_single_cal_span_drift
so2_maintenance
nox_maintenance
co_maintenance
o3_maintenance
teom_maintenance
ozonePrecursor_maintenance
aio_maintenance
so2_repair
nox_repair
co_repair
o3_repair
teom_repair
aio_repair
ozonePrecursor_repair
so2_flag
nox_flag
o3_flag
co_flag
aio_flag
ozone_precursor_flag
teom_flag
1 Record Date
2 Station
3 teom_teom_a_1-hr_mass_conc
4 teom_teom_b_1-hr_mass_conc
5 nox_no
6 nox_no2
7 nox_nox
8 so2_so2
9 co_co
10 o3_o3
11 ozonePrecursor_n-Hexane
12 ozonePrecursor_Benzene
13 ozonePrecursor_2_2_4-Trimethylpentane
14 ozonePrecursor_n-Heptane
15 ozonePrecursor_Toluene
16 ozonePrecursor_n-Octane
17 ozonePrecursor_Ethylbenzene
18 ozonePrecursor_m_p-Xylene
19 ozonePrecursor_Styrene
20 ozonePrecursor_o-Xylene
21 ozonePrecursor_1_3_5-Trimethylbenzene
22 ozonePrecursor_1_2_4-Trimethylbenzene
23 ozonePrecursor_1_2_3-Trimethylbenzene
24 ozonePrecursor_Ethane
25 ozonePrecursor_Ethene
26 ozonePrecursor_Propane
27 ozonePrecursor_Propene
28 ozonePrecursor_i-Butane
29 ozonePrecursor_n-Butane
30 ozonePrecursor_Acetylene
31 ozonePrecursor_trans-2-Butene
32 ozonePrecursor_1-Butene
33 ozonePrecursor_cis-2-Butene
34 ozonePrecursor_i-Pentane
35 ozonePrecursor_n-Pentane
36 ozonePrecursor_1_3-Butadiene
37 ozonePrecursor_trans-2-Pentene
38 ozonePrecursor_1-Pentene
39 ozonePrecursor_cis-2-Pentene
40 ozonePrecursor_2-Methylpentane
41 ozonePrecursor_n-Hexane(VOC)
42 ozonePrecursor_Isoprene
43 aio_wind_speed
44 aio_wind_direction
45 aio_ambient_temperature
46 aio_relative_humidity
47 aio_solar_radiation
48 nox_no_daily_Qccheck_zero_actual
49 nox_no_daily_Qccheck_zero_target
50 nox_no_daily_Qccheck_zero_drift
51 nox_no_daily_Qccheck_span_actual
52 nox_no_daily_Qccheck_span_target
53 nox_no_daily_Qccheck_span_drift
54 nox_no2_daily_Qccheck_zero_target
55 nox_no2_daily_Qccheck_zero_actual
56 nox_no2_daily_Qccheck_zero_drift
57 nox_no2_daily_Qccheck_span_actual
58 nox_no2_daily_Qccheck_span_target
59 nox_no2_daily_Qccheck_span_drift
60 nox_nox_daily_Qccheck_zero_actual
61 nox_nox_daily_Qccheck_zero_target
62 nox_nox_daily_Qccheck_zero_drift
63 nox_nox_daily_Qccheck_span_actual
64 nox_nox_daily_Qccheck_span_target
65 nox_nox_daily_Qccheck_span_drift
66 so2_so2_daily_Qccheck_zero_actual
67 so2_so2_daily_Qccheck_zero_target
68 so2_so2_daily_Qccheck_zero_drift
69 so2_so2_daily_Qccheck_span_actual
70 so2_so2_daily_Qccheck_span_target
71 so2_so2_daily_Qccheck_span_drift
72 co_co_daily_Qccheck_zero_actual
73 co_co_daily_Qccheck_zero_target
74 co_co_daily_Qccheck_zero_drift
75 co_co_daily_Qccheck_span_actual
76 co_co_daily_Qccheck_span_target
77 co_co_daily_Qccheck_span_drift
78 o3_o3_daily_Qccheck_zero_actual
79 o3_o3_daily_Qccheck_zero_target
80 o3_o3_daily_Qccheck_zero_drift
81 o3_o3_daily_Qccheck_span_actual
82 o3_o3_daily_Qccheck_span_target
83 o3_o3_daily_Qccheck_span_drift
84 ozonePrecursor_n-Hexane_daily_Qccheck_span_drift
85 ozonePrecursor_Benzene_daily_Qccheck_span_drift
86 ozonePrecursor_2_2_4-Trimethylpentane_daily_Qccheck_span_drift
87 ozonePrecursor_n-Heptane_daily_Qccheck_span_drift
88 ozonePrecursor_Toluene_daily_Qccheck_span_drift
89 ozonePrecursor_n-Octane_daily_Qccheck_span_drift
90 ozonePrecursor_Ethylbenzene_daily_Qccheck_span_drift
91 ozonePrecursor_m_p-Xylene_daily_Qccheck_span_drift
92 ozonePrecursor_Styrene_daily_Qccheck_span_drift
93 ozonePrecursor_o-Xylene_daily_Qccheck_span_drift
94 ozonePrecursor_1_3_5-Trimethylbenzene_daily_Qccheck_span_drift
95 ozonePrecursor_1_2_4-Trimethylbenzene_daily_Qccheck_span_drift
96 ozonePrecursor_1_2_3-Trimethylbenzene_daily_Qccheck_span_drift
97 ozonePrecursor_Ethane_daily_Qccheck_span_drift
98 ozonePrecursor_Ethene_daily_Qccheck_span_drift
99 ozonePrecursor_Propane_daily_Qccheck_span_drift
100 ozonePrecursor_Propene_daily_Qccheck_span_drift
101 ozonePrecursor_i-Butane_daily_Qccheck_span_drift
102 ozonePrecursor_n-Butane_daily_Qccheck_span_drift
103 ozonePrecursor_Acetylene_daily_Qccheck_span_drift
104 ozonePrecursor_trans-2-Butene_daily_Qccheck_span_drift
105 ozonePrecursor_1-Butene_daily_Qccheck_span_drift
106 ozonePrecursor_cis-2-Butene_daily_Qccheck_span_drift
107 ozonePrecursor_i-Pentane_daily_Qccheck_span_drift
108 ozonePrecursor_n-Pentane_daily_Qccheck_span_drift
109 ozonePrecursor_1_3-Butadiene_daily_Qccheck_span_drift
110 ozonePrecursor_trans-2-Pentene_daily_Qccheck_span_drift
111 ozonePrecursor_cis-2-Pentene_daily_Qccheck_span_drift
112 ozonePrecursor_2-Methylpentane_daily_Qccheck_span_drift
113 ozonePrecursor_n-Hexane(VOC)_daily_Qccheck_span_drift
114 ozonePrecursor_Isoprene_daily_Qccheck_span_drift
115 nox_no_single_cal_zero_actual
116 nox_no_single_cal_zero_target
117 nox_no_single_cal_zero_drift
118 nox_no_single_cal_span_actual
119 nox_no_single_cal_span_target
120 nox_no_single_cal_span_drift
121 nox_no2_single_cal_zero_actual
122 nox_no2_single_cal_zero_target
123 nox_no2_single_cal_zero_drift
124 nox_no2_single_cal_span_actual
125 nox_no2_single_cal_span_target
126 nox_no2_single_cal_span_drift
127 nox_nox_single_cal_zero_actual
128 nox_nox_single_cal_zero_target
129 nox_nox_single_cal_zero_drift
130 nox_nox_single_cal_span_actual
131 nox_nox_single_cal_span_target
132 nox_nox_single_cal_span_drift
133 so2_so2_single_cal_zero_actual
134 so2_so2_single_cal_zero_target
135 so2_so2_single_cal_zero_drift
136 so2_so2_single_cal_span_actual
137 so2_so2_single_cal_span_target
138 so2_so2_single_cal_span_drift
139 co_co_single_cal_zero_actual
140 co_co_single_cal_zero_target
141 co_co_single_cal_zero_drift
142 co_co_single_cal_span_actual
143 co_co_single_cal_span_target
144 co_co_single_cal_span_drift
145 o3_o3_single_cal_zero_actual
146 o3_o3_single_cal_zero_target
147 o3_o3_single_cal_zero_drift
148 o3_o3_single_cal_span_actual
149 o3_o3_single_cal_span_target
150 o3_o3_single_cal_span_drift
151 nox_no_multi_cal_zero_actual
152 nox_no_multi_cal_zero_target
153 nox_no_multi_cal_zero_drift
154 nox_no_multi_cal_span1_actual
155 nox_no_multi_cal_span1_target
156 nox_no_multi_cal_span1_drift
157 nox_no_multi_cal_span2_actual
158 nox_no_multi_cal_span2_target
159 nox_no_multi_cal_span2_drift
160 nox_no_multi_cal_span3_actual
161 nox_no_multi_cal_span3_target
162 nox_no_multi_cal_span3_drift
163 nox_no_multi_cal_span4_actual
164 nox_no_multi_cal_span4_target
165 nox_no_multi_cal_span4_drift
166 nox_no2_multi_cal_zero_actual
167 nox_no2_multi_cal_zero_target
168 nox_no2_multi_cal_zero_drift
169 nox_no2_multi_cal_span1_actual
170 nox_no2_multi_cal_span1_target
171 nox_no2_multi_cal_span1_drift
172 nox_no2_multi_cal_span2_actual
173 nox_no2_multi_cal_span2_target
174 nox_no2_multi_cal_span2_drift
175 nox_no2_multi_cal_span3_actual
176 nox_no2_multi_cal_span3_target
177 nox_no2_multi_cal_span3_drift
178 nox_no2_multi_cal_span4_actual
179 nox_no2_multi_cal_span4_target
180 nox_no2_multi_cal_span4_drift
181 nox_nox_multi_cal_zero_actual
182 nox_nox_multi_cal_zero_target
183 nox_nox_multi_cal_zero_drift
184 nox_nox_multi_cal_span1_actual
185 nox_nox_multi_cal_span1_target
186 nox_nox_multi_cal_span1_drift
187 nox_nox_multi_cal_span2_actual
188 nox_nox_multi_cal_span2_target
189 nox_nox_multi_cal_span2_drift
190 nox_nox_multi_cal_span3_actual
191 nox_nox_multi_cal_span3_target
192 nox_nox_multi_cal_span3_drift
193 nox_nox_multi_cal_span4_actual
194 nox_nox_multi_cal_span4_target
195 nox_nox_multi_cal_span4_drift
196 so2_so2_multi_cal_zero_actual
197 so2_so2_multi_cal_zero_target
198 so2_so2_multi_cal_zero_drift
199 so2_so2_multi_cal_span1_actual
200 so2_so2_multi_cal_span1_target
201 so2_so2_multi_cal_span1_drift
202 so2_so2_multi_cal_span2_actual
203 so2_so2_multi_cal_span2_target
204 so2_so2_multi_cal_span2_drift
205 so2_so2_multi_cal_span3_actual
206 so2_so2_multi_cal_span3_target
207 so2_so2_multi_cal_span3_drift
208 so2_so2_multi_cal_span4_actual
209 so2_so2_multi_cal_span4_target
210 so2_so2_multi_cal_span4_drift
211 co_co_multi_cal_zero_actual
212 co_co_multi_cal_zero_target
213 co_co_multi_cal_zero_drift
214 co_co_multi_cal_span1_actual
215 co_co_multi_cal_span1_target
216 co_co_multi_cal_span1_drift
217 co_co_multi_cal_span2_actual
218 co_co_multi_cal_span2_target
219 co_co_multi_cal_span2_drift
220 co_co_multi_cal_span3_actual
221 co_co_multi_cal_span3_target
222 co_co_multi_cal_span3_drift
223 co_co_multi_cal_span4_actual
224 co_co_multi_cal_span4_target
225 co_co_multi_cal_span4_drift
226 o3_o3_multi_cal_zero_actual
227 o3_o3_multi_cal_zero_target
228 o3_o3_multi_cal_zero_drift
229 o3_o3_multi_cal_span1_actual
230 o3_o3_multi_cal_span1_target
231 o3_o3_multi_cal_span1_drift
232 o3_o3_multi_cal_span2_actual
233 o3_o3_multi_cal_span2_target
234 o3_o3_multi_cal_span2_drift
235 o3_o3_multi_cal_span3_actual
236 o3_o3_multi_cal_span3_target
237 o3_o3_multi_cal_span3_drift
238 o3_o3_multi_cal_span4_actual
239 o3_o3_multi_cal_span4_target
240 o3_o3_multi_cal_span4_drift
241 ozonePrecursor_n-Hexane_single_cal_span_actual
242 ozonePrecursor_n-Hexane_single_cal_span_target
243 ozonePrecursor_n-Hexane_single_cal_span_drift
244 ozonePrecursor_Benzene_single_cal_span_actual
245 ozonePrecursor_Benzene_single_cal_span_target
246 ozonePrecursor_Benzene_single_cal_span_drift
247 ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_actual
248 ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_target
249 ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_drift
250 ozonePrecursor_n-Heptane_single_cal_span_actual
251 ozonePrecursor_n-Heptane_single_cal_span_target
252 ozonePrecursor_n-Heptane_single_cal_span_drift
253 ozonePrecursor_Toluene_single_cal_span_actual
254 ozonePrecursor_Toluene_single_cal_span_target
255 ozonePrecursor_Toluene_single_cal_span_drift
256 ozonePrecursor_n-Octane_single_cal_span_actual
257 ozonePrecursor_n-Octane_single_cal_span_target
258 ozonePrecursor_n-Octane_single_cal_span_drift
259 ozonePrecursor_Ethylbenzene_single_cal_span_actual
260 ozonePrecursor_Ethylbenzene_single_cal_span_target
261 ozonePrecursor_Ethylbenzene_single_cal_span_drift
262 ozonePrecursor_m_p-Xylene_single_cal_span_actual
263 ozonePrecursor_m_p-Xylene_single_cal_span_target
264 ozonePrecursor_m_p-Xylene_single_cal_span_drift
265 ozonePrecursor_Styrene_single_cal_span_actual
266 ozonePrecursor_Styrene_single_cal_span_target
267 ozonePrecursor_Styrene_single_cal_span_drift
268 ozonePrecursor_o-Xylene_single_cal_span_actual
269 ozonePrecursor_o-Xylene_single_cal_span_target
270 ozonePrecursor_o-Xylene_single_cal_span_drift
271 ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_actual
272 ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_target
273 ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_drift
274 ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_actual
275 ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_target
276 ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_drift
277 ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_actual
278 ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_target
279 ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_drift
280 ozonePrecursor_Ethane_single_cal_span_actual
281 ozonePrecursor_Ethane_single_cal_span_target
282 ozonePrecursor_Ethane_single_cal_span_drift
283 ozonePrecursor_Ethene_single_cal_span_actual
284 ozonePrecursor_Ethene_single_cal_span_target
285 ozonePrecursor_Ethene_single_cal_span_drift
286 ozonePrecursor_Propane_single_cal_span_actual
287 ozonePrecursor_Propane_single_cal_span_target
288 ozonePrecursor_Propane_single_cal_span_drift
289 ozonePrecursor_Propene_single_cal_span_actual
290 ozonePrecursor_Propene_single_cal_span_target
291 ozonePrecursor_Propene_single_cal_span_drift
292 ozonePrecursor_i-Butane_single_cal_span_actual
293 ozonePrecursor_i-Butane_single_cal_span_target
294 ozonePrecursor_i-Butane_single_cal_span_drift
295 ozonePrecursor_n-Butane_single_cal_span_actual
296 ozonePrecursor_n-Butane_single_cal_span_target
297 ozonePrecursor_n-Butane_single_cal_span_drift
298 ozonePrecursor_Acetylene_single_cal_span_actual
299 ozonePrecursor_Acetylene_single_cal_span_target
300 ozonePrecursor_Acetylene_single_cal_span_drift
301 ozonePrecursor_trans-2-Butene_single_cal_span_actual
302 ozonePrecursor_trans-2-Butene_single_cal_span_target
303 ozonePrecursor_trans-2-Butene_single_cal_span_drift
304 ozonePrecursor_1-Butene_single_cal_span_actual
305 ozonePrecursor_1-Butene_single_cal_span_target
306 ozonePrecursor_1-Butene_single_cal_span_drift
307 ozonePrecursor_cis-2-Butene_single_cal_span_actual
308 ozonePrecursor_cis-2-Butene_single_cal_span_target
309 ozonePrecursor_cis-2-Butene_single_cal_span_drift
310 ozonePrecursor_i-Pentane_single_cal_span_actual
311 ozonePrecursor_i-Pentane_single_cal_span_target
312 ozonePrecursor_i-Pentane_single_cal_span_drift
313 ozonePrecursor_n-Pentane_single_cal_span_actual
314 ozonePrecursor_n-Pentane_single_cal_span_target
315 ozonePrecursor_n-Pentane_single_cal_span_drift
316 ozonePrecursor_1_3-Butadiene_single_cal_span_actual
317 ozonePrecursor_1_3-Butadiene_single_cal_span_target
318 ozonePrecursor_1_3-Butadiene_single_cal_span_drift
319 ozonePrecursor_trans-2-Pentene_single_cal_span_actual
320 ozonePrecursor_trans-2-Pentene_single_cal_span_target
321 ozonePrecursor_trans-2-Pentene_single_cal_span_drift
322 ozonePrecursor_1-Pentene_single_cal_span_actual
323 ozonePrecursor_1-Pentene_single_cal_span_target
324 ozonePrecursor_1-Pentene_single_cal_span_drift
325 ozonePrecursor_cis-2-Pentene_single_cal_span_actual
326 ozonePrecursor_cis-2-Pentene_single_cal_span_target
327 ozonePrecursor_cis-2-Pentene_single_cal_span_drift
328 ozonePrecursor_2-Methylpentane_single_cal_span_actual
329 ozonePrecursor_2-Methylpentane_single_cal_span_target
330 ozonePrecursor_2-Methylpentane_single_cal_span_drift
331 ozonePrecursor_n-Hexane(VOC)_single_cal_span_actual
332 ozonePrecursor_n-Hexane(VOC)_single_cal_span_target
333 ozonePrecursor_n-Hexane(VOC)_single_cal_span_drift
334 ozonePrecursor_Isoprene_single_cal_span_actual
335 ozonePrecursor_Isoprene_single_cal_span_target
336 ozonePrecursor_Isoprene_single_cal_span_drift
337 so2_maintenance
338 nox_maintenance
339 co_maintenance
340 o3_maintenance
341 teom_maintenance
342 ozonePrecursor_maintenance
343 aio_maintenance
344 so2_repair
345 nox_repair
346 co_repair
347 o3_repair
348 teom_repair
349 aio_repair
350 ozonePrecursor_repair
351 so2_flag
352 nox_flag
353 o3_flag
354 co_flag
355 aio_flag
356 ozone_precursor_flag
357 teom_flag

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
aio_wind_speed
aio_wind_direction
aio_ambient_temperature
aio_relative_humidity
aio_solar_radiation
aio_maintenance
aio_repair
aio_flag
1 aio_wind_speed
2 aio_wind_direction
3 aio_ambient_temperature
4 aio_relative_humidity
5 aio_solar_radiation
6 aio_maintenance
7 aio_repair
8 aio_flag

View File

@ -0,0 +1,31 @@
co_co
co_co_daily_Qccheck_zero_actual
co_co_daily_Qccheck_zero_target
co_co_daily_Qccheck_zero_drift
co_co_daily_Qccheck_span_actual
co_co_daily_Qccheck_span_target
co_co_daily_Qccheck_span_drift
co_co_single_cal_zero_actual
co_co_single_cal_zero_target
co_co_single_cal_zero_drift
co_co_single_cal_span_actual
co_co_single_cal_span_target
co_co_single_cal_span_drift
co_co_multi_cal_zero_actual
co_co_multi_cal_zero_target
co_co_multi_cal_zero_drift
co_co_multi_cal_span1_actual
co_co_multi_cal_span1_target
co_co_multi_cal_span1_drift
co_co_multi_cal_span2_actual
co_co_multi_cal_span2_target
co_co_multi_cal_span2_drift
co_co_multi_cal_span3_actual
co_co_multi_cal_span3_target
co_co_multi_cal_span3_drift
co_co_multi_cal_span4_actual
co_co_multi_cal_span4_target
co_co_multi_cal_span4_drift
co_maintenance
co_repair
co_flag
1 co_co
2 co_co_daily_Qccheck_zero_actual
3 co_co_daily_Qccheck_zero_target
4 co_co_daily_Qccheck_zero_drift
5 co_co_daily_Qccheck_span_actual
6 co_co_daily_Qccheck_span_target
7 co_co_daily_Qccheck_span_drift
8 co_co_single_cal_zero_actual
9 co_co_single_cal_zero_target
10 co_co_single_cal_zero_drift
11 co_co_single_cal_span_actual
12 co_co_single_cal_span_target
13 co_co_single_cal_span_drift
14 co_co_multi_cal_zero_actual
15 co_co_multi_cal_zero_target
16 co_co_multi_cal_zero_drift
17 co_co_multi_cal_span1_actual
18 co_co_multi_cal_span1_target
19 co_co_multi_cal_span1_drift
20 co_co_multi_cal_span2_actual
21 co_co_multi_cal_span2_target
22 co_co_multi_cal_span2_drift
23 co_co_multi_cal_span3_actual
24 co_co_multi_cal_span3_target
25 co_co_multi_cal_span3_drift
26 co_co_multi_cal_span4_actual
27 co_co_multi_cal_span4_target
28 co_co_multi_cal_span4_drift
29 co_maintenance
30 co_repair
31 co_flag

View File

@ -0,0 +1,87 @@
nox_no
nox_no2
nox_nox
nox_no_daily_Qccheck_zero_actual
nox_no_daily_Qccheck_zero_target
nox_no_daily_Qccheck_zero_drift
nox_no_daily_Qccheck_span_actual
nox_no_daily_Qccheck_span_target
nox_no_daily_Qccheck_span_drift
nox_no2_daily_Qccheck_zero_target
nox_no2_daily_Qccheck_zero_actual
nox_no2_daily_Qccheck_zero_drift
nox_no2_daily_Qccheck_span_actual
nox_no2_daily_Qccheck_span_target
nox_no2_daily_Qccheck_span_drift
nox_nox_daily_Qccheck_zero_actual
nox_nox_daily_Qccheck_zero_target
nox_nox_daily_Qccheck_zero_drift
nox_nox_daily_Qccheck_span_actual
nox_nox_daily_Qccheck_span_target
nox_nox_daily_Qccheck_span_drift
nox_no_single_cal_zero_actual
nox_no_single_cal_zero_target
nox_no_single_cal_zero_drift
nox_no_single_cal_span_actual
nox_no_single_cal_span_target
nox_no_single_cal_span_drift
nox_no2_single_cal_zero_actual
nox_no2_single_cal_zero_target
nox_no2_single_cal_zero_drift
nox_no2_single_cal_span_actual
nox_no2_single_cal_span_target
nox_no2_single_cal_span_drift
nox_nox_single_cal_zero_actual
nox_nox_single_cal_zero_target
nox_nox_single_cal_zero_drift
nox_nox_single_cal_span_actual
nox_nox_single_cal_span_target
nox_nox_single_cal_span_drift
nox_no_multi_cal_zero_actual
nox_no_multi_cal_zero_target
nox_no_multi_cal_zero_drift
nox_no_multi_cal_span1_actual
nox_no_multi_cal_span1_target
nox_no_multi_cal_span1_drift
nox_no_multi_cal_span2_actual
nox_no_multi_cal_span2_target
nox_no_multi_cal_span2_drift
nox_no_multi_cal_span3_actual
nox_no_multi_cal_span3_target
nox_no_multi_cal_span3_drift
nox_no_multi_cal_span4_actual
nox_no_multi_cal_span4_target
nox_no_multi_cal_span4_drift
nox_no2_multi_cal_zero_actual
nox_no2_multi_cal_zero_target
nox_no2_multi_cal_zero_drift
nox_no2_multi_cal_span1_actual
nox_no2_multi_cal_span1_target
nox_no2_multi_cal_span1_drift
nox_no2_multi_cal_span2_actual
nox_no2_multi_cal_span2_target
nox_no2_multi_cal_span2_drift
nox_no2_multi_cal_span3_actual
nox_no2_multi_cal_span3_target
nox_no2_multi_cal_span3_drift
nox_no2_multi_cal_span4_actual
nox_no2_multi_cal_span4_target
nox_no2_multi_cal_span4_drift
nox_nox_multi_cal_zero_actual
nox_nox_multi_cal_zero_target
nox_nox_multi_cal_zero_drift
nox_nox_multi_cal_span1_actual
nox_nox_multi_cal_span1_target
nox_nox_multi_cal_span1_drift
nox_nox_multi_cal_span2_actual
nox_nox_multi_cal_span2_target
nox_nox_multi_cal_span2_drift
nox_nox_multi_cal_span3_actual
nox_nox_multi_cal_span3_target
nox_nox_multi_cal_span3_drift
nox_nox_multi_cal_span4_actual
nox_nox_multi_cal_span4_target
nox_nox_multi_cal_span4_drift
nox_maintenance
nox_repair
nox_flag
1 nox_no
2 nox_no2
3 nox_nox
4 nox_no_daily_Qccheck_zero_actual
5 nox_no_daily_Qccheck_zero_target
6 nox_no_daily_Qccheck_zero_drift
7 nox_no_daily_Qccheck_span_actual
8 nox_no_daily_Qccheck_span_target
9 nox_no_daily_Qccheck_span_drift
10 nox_no2_daily_Qccheck_zero_target
11 nox_no2_daily_Qccheck_zero_actual
12 nox_no2_daily_Qccheck_zero_drift
13 nox_no2_daily_Qccheck_span_actual
14 nox_no2_daily_Qccheck_span_target
15 nox_no2_daily_Qccheck_span_drift
16 nox_nox_daily_Qccheck_zero_actual
17 nox_nox_daily_Qccheck_zero_target
18 nox_nox_daily_Qccheck_zero_drift
19 nox_nox_daily_Qccheck_span_actual
20 nox_nox_daily_Qccheck_span_target
21 nox_nox_daily_Qccheck_span_drift
22 nox_no_single_cal_zero_actual
23 nox_no_single_cal_zero_target
24 nox_no_single_cal_zero_drift
25 nox_no_single_cal_span_actual
26 nox_no_single_cal_span_target
27 nox_no_single_cal_span_drift
28 nox_no2_single_cal_zero_actual
29 nox_no2_single_cal_zero_target
30 nox_no2_single_cal_zero_drift
31 nox_no2_single_cal_span_actual
32 nox_no2_single_cal_span_target
33 nox_no2_single_cal_span_drift
34 nox_nox_single_cal_zero_actual
35 nox_nox_single_cal_zero_target
36 nox_nox_single_cal_zero_drift
37 nox_nox_single_cal_span_actual
38 nox_nox_single_cal_span_target
39 nox_nox_single_cal_span_drift
40 nox_no_multi_cal_zero_actual
41 nox_no_multi_cal_zero_target
42 nox_no_multi_cal_zero_drift
43 nox_no_multi_cal_span1_actual
44 nox_no_multi_cal_span1_target
45 nox_no_multi_cal_span1_drift
46 nox_no_multi_cal_span2_actual
47 nox_no_multi_cal_span2_target
48 nox_no_multi_cal_span2_drift
49 nox_no_multi_cal_span3_actual
50 nox_no_multi_cal_span3_target
51 nox_no_multi_cal_span3_drift
52 nox_no_multi_cal_span4_actual
53 nox_no_multi_cal_span4_target
54 nox_no_multi_cal_span4_drift
55 nox_no2_multi_cal_zero_actual
56 nox_no2_multi_cal_zero_target
57 nox_no2_multi_cal_zero_drift
58 nox_no2_multi_cal_span1_actual
59 nox_no2_multi_cal_span1_target
60 nox_no2_multi_cal_span1_drift
61 nox_no2_multi_cal_span2_actual
62 nox_no2_multi_cal_span2_target
63 nox_no2_multi_cal_span2_drift
64 nox_no2_multi_cal_span3_actual
65 nox_no2_multi_cal_span3_target
66 nox_no2_multi_cal_span3_drift
67 nox_no2_multi_cal_span4_actual
68 nox_no2_multi_cal_span4_target
69 nox_no2_multi_cal_span4_drift
70 nox_nox_multi_cal_zero_actual
71 nox_nox_multi_cal_zero_target
72 nox_nox_multi_cal_zero_drift
73 nox_nox_multi_cal_span1_actual
74 nox_nox_multi_cal_span1_target
75 nox_nox_multi_cal_span1_drift
76 nox_nox_multi_cal_span2_actual
77 nox_nox_multi_cal_span2_target
78 nox_nox_multi_cal_span2_drift
79 nox_nox_multi_cal_span3_actual
80 nox_nox_multi_cal_span3_target
81 nox_nox_multi_cal_span3_drift
82 nox_nox_multi_cal_span4_actual
83 nox_nox_multi_cal_span4_target
84 nox_nox_multi_cal_span4_drift
85 nox_maintenance
86 nox_repair
87 nox_flag

View File

@ -0,0 +1,31 @@
o3_o3
o3_o3_daily_Qccheck_zero_actual
o3_o3_daily_Qccheck_zero_target
o3_o3_daily_Qccheck_zero_drift
o3_o3_daily_Qccheck_span_actual
o3_o3_daily_Qccheck_span_target
o3_o3_daily_Qccheck_span_drift
o3_o3_single_cal_zero_actual
o3_o3_single_cal_zero_target
o3_o3_single_cal_zero_drift
o3_o3_single_cal_span_actual
o3_o3_single_cal_span_target
o3_o3_single_cal_span_drift
o3_o3_multi_cal_zero_actual
o3_o3_multi_cal_zero_target
o3_o3_multi_cal_zero_drift
o3_o3_multi_cal_span1_actual
o3_o3_multi_cal_span1_target
o3_o3_multi_cal_span1_drift
o3_o3_multi_cal_span2_actual
o3_o3_multi_cal_span2_target
o3_o3_multi_cal_span2_drift
o3_o3_multi_cal_span3_actual
o3_o3_multi_cal_span3_target
o3_o3_multi_cal_span3_drift
o3_o3_multi_cal_span4_actual
o3_o3_multi_cal_span4_target
o3_o3_multi_cal_span4_drift
o3_maintenance
o3_repair
o3_flag
1 o3_o3
2 o3_o3_daily_Qccheck_zero_actual
3 o3_o3_daily_Qccheck_zero_target
4 o3_o3_daily_Qccheck_zero_drift
5 o3_o3_daily_Qccheck_span_actual
6 o3_o3_daily_Qccheck_span_target
7 o3_o3_daily_Qccheck_span_drift
8 o3_o3_single_cal_zero_actual
9 o3_o3_single_cal_zero_target
10 o3_o3_single_cal_zero_drift
11 o3_o3_single_cal_span_actual
12 o3_o3_single_cal_span_target
13 o3_o3_single_cal_span_drift
14 o3_o3_multi_cal_zero_actual
15 o3_o3_multi_cal_zero_target
16 o3_o3_multi_cal_zero_drift
17 o3_o3_multi_cal_span1_actual
18 o3_o3_multi_cal_span1_target
19 o3_o3_multi_cal_span1_drift
20 o3_o3_multi_cal_span2_actual
21 o3_o3_multi_cal_span2_target
22 o3_o3_multi_cal_span2_drift
23 o3_o3_multi_cal_span3_actual
24 o3_o3_multi_cal_span3_target
25 o3_o3_multi_cal_span3_drift
26 o3_o3_multi_cal_span4_actual
27 o3_o3_multi_cal_span4_target
28 o3_o3_multi_cal_span4_drift
29 o3_maintenance
30 o3_repair
31 o3_flag

View File

@ -0,0 +1,162 @@
ozonePrecursor_n-Hexane
ozonePrecursor_Benzene
ozonePrecursor_2_2_4-Trimethylpentane
ozonePrecursor_n-Heptane
ozonePrecursor_Toluene
ozonePrecursor_n-Octane
ozonePrecursor_Ethylbenzene
ozonePrecursor_m_p-Xylene
ozonePrecursor_Styrene
ozonePrecursor_o-Xylene
ozonePrecursor_1_3_5-Trimethylbenzene
ozonePrecursor_1_2_4-Trimethylbenzene
ozonePrecursor_1_2_3-Trimethylbenzene
ozonePrecursor_Ethane
ozonePrecursor_Ethene
ozonePrecursor_Propane
ozonePrecursor_Propene
ozonePrecursor_i-Butane
ozonePrecursor_n-Butane
ozonePrecursor_Acetylene
ozonePrecursor_trans-2-Butene
ozonePrecursor_1-Butene
ozonePrecursor_cis-2-Butene
ozonePrecursor_i-Pentane
ozonePrecursor_n-Pentane
ozonePrecursor_1_3-Butadiene
ozonePrecursor_trans-2-Pentene
ozonePrecursor_1-Pentene
ozonePrecursor_cis-2-Pentene
ozonePrecursor_2-Methylpentane
ozonePrecursor_n-Hexane(VOC)
ozonePrecursor_Isoprene
ozonePrecursor_n-Hexane_daily_Qccheck_span_drift
ozonePrecursor_Benzene_daily_Qccheck_span_drift
ozonePrecursor_2_2_4-Trimethylpentane_daily_Qccheck_span_drift
ozonePrecursor_n-Heptane_daily_Qccheck_span_drift
ozonePrecursor_Toluene_daily_Qccheck_span_drift
ozonePrecursor_n-Octane_daily_Qccheck_span_drift
ozonePrecursor_Ethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_m_p-Xylene_daily_Qccheck_span_drift
ozonePrecursor_Styrene_daily_Qccheck_span_drift
ozonePrecursor_o-Xylene_daily_Qccheck_span_drift
ozonePrecursor_1_3_5-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_1_2_4-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_1_2_3-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_Ethane_daily_Qccheck_span_drift
ozonePrecursor_Ethene_daily_Qccheck_span_drift
ozonePrecursor_Propane_daily_Qccheck_span_drift
ozonePrecursor_Propene_daily_Qccheck_span_drift
ozonePrecursor_i-Butane_daily_Qccheck_span_drift
ozonePrecursor_n-Butane_daily_Qccheck_span_drift
ozonePrecursor_Acetylene_daily_Qccheck_span_drift
ozonePrecursor_trans-2-Butene_daily_Qccheck_span_drift
ozonePrecursor_1-Butene_daily_Qccheck_span_drift
ozonePrecursor_cis-2-Butene_daily_Qccheck_span_drift
ozonePrecursor_i-Pentane_daily_Qccheck_span_drift
ozonePrecursor_n-Pentane_daily_Qccheck_span_drift
ozonePrecursor_1_3-Butadiene_daily_Qccheck_span_drift
ozonePrecursor_trans-2-Pentene_daily_Qccheck_span_drift
ozonePrecursor_cis-2-Pentene_daily_Qccheck_span_drift
ozonePrecursor_2-Methylpentane_daily_Qccheck_span_drift
ozonePrecursor_n-Hexane(VOC)_daily_Qccheck_span_drift
ozonePrecursor_Isoprene_daily_Qccheck_span_drift
ozonePrecursor_n-Hexane_single_cal_span_actual
ozonePrecursor_n-Hexane_single_cal_span_target
ozonePrecursor_n-Hexane_single_cal_span_drift
ozonePrecursor_Benzene_single_cal_span_actual
ozonePrecursor_Benzene_single_cal_span_target
ozonePrecursor_Benzene_single_cal_span_drift
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_actual
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_target
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_drift
ozonePrecursor_n-Heptane_single_cal_span_actual
ozonePrecursor_n-Heptane_single_cal_span_target
ozonePrecursor_n-Heptane_single_cal_span_drift
ozonePrecursor_Toluene_single_cal_span_actual
ozonePrecursor_Toluene_single_cal_span_target
ozonePrecursor_Toluene_single_cal_span_drift
ozonePrecursor_n-Octane_single_cal_span_actual
ozonePrecursor_n-Octane_single_cal_span_target
ozonePrecursor_n-Octane_single_cal_span_drift
ozonePrecursor_Ethylbenzene_single_cal_span_actual
ozonePrecursor_Ethylbenzene_single_cal_span_target
ozonePrecursor_Ethylbenzene_single_cal_span_drift
ozonePrecursor_m_p-Xylene_single_cal_span_actual
ozonePrecursor_m_p-Xylene_single_cal_span_target
ozonePrecursor_m_p-Xylene_single_cal_span_drift
ozonePrecursor_Styrene_single_cal_span_actual
ozonePrecursor_Styrene_single_cal_span_target
ozonePrecursor_Styrene_single_cal_span_drift
ozonePrecursor_o-Xylene_single_cal_span_actual
ozonePrecursor_o-Xylene_single_cal_span_target
ozonePrecursor_o-Xylene_single_cal_span_drift
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_Ethane_single_cal_span_actual
ozonePrecursor_Ethane_single_cal_span_target
ozonePrecursor_Ethane_single_cal_span_drift
ozonePrecursor_Ethene_single_cal_span_actual
ozonePrecursor_Ethene_single_cal_span_target
ozonePrecursor_Ethene_single_cal_span_drift
ozonePrecursor_Propane_single_cal_span_actual
ozonePrecursor_Propane_single_cal_span_target
ozonePrecursor_Propane_single_cal_span_drift
ozonePrecursor_Propene_single_cal_span_actual
ozonePrecursor_Propene_single_cal_span_target
ozonePrecursor_Propene_single_cal_span_drift
ozonePrecursor_i-Butane_single_cal_span_actual
ozonePrecursor_i-Butane_single_cal_span_target
ozonePrecursor_i-Butane_single_cal_span_drift
ozonePrecursor_n-Butane_single_cal_span_actual
ozonePrecursor_n-Butane_single_cal_span_target
ozonePrecursor_n-Butane_single_cal_span_drift
ozonePrecursor_Acetylene_single_cal_span_actual
ozonePrecursor_Acetylene_single_cal_span_target
ozonePrecursor_Acetylene_single_cal_span_drift
ozonePrecursor_trans-2-Butene_single_cal_span_actual
ozonePrecursor_trans-2-Butene_single_cal_span_target
ozonePrecursor_trans-2-Butene_single_cal_span_drift
ozonePrecursor_1-Butene_single_cal_span_actual
ozonePrecursor_1-Butene_single_cal_span_target
ozonePrecursor_1-Butene_single_cal_span_drift
ozonePrecursor_cis-2-Butene_single_cal_span_actual
ozonePrecursor_cis-2-Butene_single_cal_span_target
ozonePrecursor_cis-2-Butene_single_cal_span_drift
ozonePrecursor_i-Pentane_single_cal_span_actual
ozonePrecursor_i-Pentane_single_cal_span_target
ozonePrecursor_i-Pentane_single_cal_span_drift
ozonePrecursor_n-Pentane_single_cal_span_actual
ozonePrecursor_n-Pentane_single_cal_span_target
ozonePrecursor_n-Pentane_single_cal_span_drift
ozonePrecursor_1_3-Butadiene_single_cal_span_actual
ozonePrecursor_1_3-Butadiene_single_cal_span_target
ozonePrecursor_1_3-Butadiene_single_cal_span_drift
ozonePrecursor_trans-2-Pentene_single_cal_span_actual
ozonePrecursor_trans-2-Pentene_single_cal_span_target
ozonePrecursor_trans-2-Pentene_single_cal_span_drift
ozonePrecursor_1-Pentene_single_cal_span_actual
ozonePrecursor_1-Pentene_single_cal_span_target
ozonePrecursor_1-Pentene_single_cal_span_drift
ozonePrecursor_cis-2-Pentene_single_cal_span_actual
ozonePrecursor_cis-2-Pentene_single_cal_span_target
ozonePrecursor_cis-2-Pentene_single_cal_span_drift
ozonePrecursor_2-Methylpentane_single_cal_span_actual
ozonePrecursor_2-Methylpentane_single_cal_span_target
ozonePrecursor_2-Methylpentane_single_cal_span_drift
ozonePrecursor_n-Hexane(VOC)_single_cal_span_actual
ozonePrecursor_n-Hexane(VOC)_single_cal_span_target
ozonePrecursor_n-Hexane(VOC)_single_cal_span_drift
ozonePrecursor_Isoprene_single_cal_span_actual
ozonePrecursor_Isoprene_single_cal_span_target
ozonePrecursor_Isoprene_single_cal_span_drift
ozonePrecursor_maintenance
ozonePrecursor_repair
ozone_precursor_flag
1 ozonePrecursor_n-Hexane
2 ozonePrecursor_Benzene
3 ozonePrecursor_2_2_4-Trimethylpentane
4 ozonePrecursor_n-Heptane
5 ozonePrecursor_Toluene
6 ozonePrecursor_n-Octane
7 ozonePrecursor_Ethylbenzene
8 ozonePrecursor_m_p-Xylene
9 ozonePrecursor_Styrene
10 ozonePrecursor_o-Xylene
11 ozonePrecursor_1_3_5-Trimethylbenzene
12 ozonePrecursor_1_2_4-Trimethylbenzene
13 ozonePrecursor_1_2_3-Trimethylbenzene
14 ozonePrecursor_Ethane
15 ozonePrecursor_Ethene
16 ozonePrecursor_Propane
17 ozonePrecursor_Propene
18 ozonePrecursor_i-Butane
19 ozonePrecursor_n-Butane
20 ozonePrecursor_Acetylene
21 ozonePrecursor_trans-2-Butene
22 ozonePrecursor_1-Butene
23 ozonePrecursor_cis-2-Butene
24 ozonePrecursor_i-Pentane
25 ozonePrecursor_n-Pentane
26 ozonePrecursor_1_3-Butadiene
27 ozonePrecursor_trans-2-Pentene
28 ozonePrecursor_1-Pentene
29 ozonePrecursor_cis-2-Pentene
30 ozonePrecursor_2-Methylpentane
31 ozonePrecursor_n-Hexane(VOC)
32 ozonePrecursor_Isoprene
33 ozonePrecursor_n-Hexane_daily_Qccheck_span_drift
34 ozonePrecursor_Benzene_daily_Qccheck_span_drift
35 ozonePrecursor_2_2_4-Trimethylpentane_daily_Qccheck_span_drift
36 ozonePrecursor_n-Heptane_daily_Qccheck_span_drift
37 ozonePrecursor_Toluene_daily_Qccheck_span_drift
38 ozonePrecursor_n-Octane_daily_Qccheck_span_drift
39 ozonePrecursor_Ethylbenzene_daily_Qccheck_span_drift
40 ozonePrecursor_m_p-Xylene_daily_Qccheck_span_drift
41 ozonePrecursor_Styrene_daily_Qccheck_span_drift
42 ozonePrecursor_o-Xylene_daily_Qccheck_span_drift
43 ozonePrecursor_1_3_5-Trimethylbenzene_daily_Qccheck_span_drift
44 ozonePrecursor_1_2_4-Trimethylbenzene_daily_Qccheck_span_drift
45 ozonePrecursor_1_2_3-Trimethylbenzene_daily_Qccheck_span_drift
46 ozonePrecursor_Ethane_daily_Qccheck_span_drift
47 ozonePrecursor_Ethene_daily_Qccheck_span_drift
48 ozonePrecursor_Propane_daily_Qccheck_span_drift
49 ozonePrecursor_Propene_daily_Qccheck_span_drift
50 ozonePrecursor_i-Butane_daily_Qccheck_span_drift
51 ozonePrecursor_n-Butane_daily_Qccheck_span_drift
52 ozonePrecursor_Acetylene_daily_Qccheck_span_drift
53 ozonePrecursor_trans-2-Butene_daily_Qccheck_span_drift
54 ozonePrecursor_1-Butene_daily_Qccheck_span_drift
55 ozonePrecursor_cis-2-Butene_daily_Qccheck_span_drift
56 ozonePrecursor_i-Pentane_daily_Qccheck_span_drift
57 ozonePrecursor_n-Pentane_daily_Qccheck_span_drift
58 ozonePrecursor_1_3-Butadiene_daily_Qccheck_span_drift
59 ozonePrecursor_trans-2-Pentene_daily_Qccheck_span_drift
60 ozonePrecursor_cis-2-Pentene_daily_Qccheck_span_drift
61 ozonePrecursor_2-Methylpentane_daily_Qccheck_span_drift
62 ozonePrecursor_n-Hexane(VOC)_daily_Qccheck_span_drift
63 ozonePrecursor_Isoprene_daily_Qccheck_span_drift
64 ozonePrecursor_n-Hexane_single_cal_span_actual
65 ozonePrecursor_n-Hexane_single_cal_span_target
66 ozonePrecursor_n-Hexane_single_cal_span_drift
67 ozonePrecursor_Benzene_single_cal_span_actual
68 ozonePrecursor_Benzene_single_cal_span_target
69 ozonePrecursor_Benzene_single_cal_span_drift
70 ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_actual
71 ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_target
72 ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_drift
73 ozonePrecursor_n-Heptane_single_cal_span_actual
74 ozonePrecursor_n-Heptane_single_cal_span_target
75 ozonePrecursor_n-Heptane_single_cal_span_drift
76 ozonePrecursor_Toluene_single_cal_span_actual
77 ozonePrecursor_Toluene_single_cal_span_target
78 ozonePrecursor_Toluene_single_cal_span_drift
79 ozonePrecursor_n-Octane_single_cal_span_actual
80 ozonePrecursor_n-Octane_single_cal_span_target
81 ozonePrecursor_n-Octane_single_cal_span_drift
82 ozonePrecursor_Ethylbenzene_single_cal_span_actual
83 ozonePrecursor_Ethylbenzene_single_cal_span_target
84 ozonePrecursor_Ethylbenzene_single_cal_span_drift
85 ozonePrecursor_m_p-Xylene_single_cal_span_actual
86 ozonePrecursor_m_p-Xylene_single_cal_span_target
87 ozonePrecursor_m_p-Xylene_single_cal_span_drift
88 ozonePrecursor_Styrene_single_cal_span_actual
89 ozonePrecursor_Styrene_single_cal_span_target
90 ozonePrecursor_Styrene_single_cal_span_drift
91 ozonePrecursor_o-Xylene_single_cal_span_actual
92 ozonePrecursor_o-Xylene_single_cal_span_target
93 ozonePrecursor_o-Xylene_single_cal_span_drift
94 ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_actual
95 ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_target
96 ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_drift
97 ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_actual
98 ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_target
99 ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_drift
100 ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_actual
101 ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_target
102 ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_drift
103 ozonePrecursor_Ethane_single_cal_span_actual
104 ozonePrecursor_Ethane_single_cal_span_target
105 ozonePrecursor_Ethane_single_cal_span_drift
106 ozonePrecursor_Ethene_single_cal_span_actual
107 ozonePrecursor_Ethene_single_cal_span_target
108 ozonePrecursor_Ethene_single_cal_span_drift
109 ozonePrecursor_Propane_single_cal_span_actual
110 ozonePrecursor_Propane_single_cal_span_target
111 ozonePrecursor_Propane_single_cal_span_drift
112 ozonePrecursor_Propene_single_cal_span_actual
113 ozonePrecursor_Propene_single_cal_span_target
114 ozonePrecursor_Propene_single_cal_span_drift
115 ozonePrecursor_i-Butane_single_cal_span_actual
116 ozonePrecursor_i-Butane_single_cal_span_target
117 ozonePrecursor_i-Butane_single_cal_span_drift
118 ozonePrecursor_n-Butane_single_cal_span_actual
119 ozonePrecursor_n-Butane_single_cal_span_target
120 ozonePrecursor_n-Butane_single_cal_span_drift
121 ozonePrecursor_Acetylene_single_cal_span_actual
122 ozonePrecursor_Acetylene_single_cal_span_target
123 ozonePrecursor_Acetylene_single_cal_span_drift
124 ozonePrecursor_trans-2-Butene_single_cal_span_actual
125 ozonePrecursor_trans-2-Butene_single_cal_span_target
126 ozonePrecursor_trans-2-Butene_single_cal_span_drift
127 ozonePrecursor_1-Butene_single_cal_span_actual
128 ozonePrecursor_1-Butene_single_cal_span_target
129 ozonePrecursor_1-Butene_single_cal_span_drift
130 ozonePrecursor_cis-2-Butene_single_cal_span_actual
131 ozonePrecursor_cis-2-Butene_single_cal_span_target
132 ozonePrecursor_cis-2-Butene_single_cal_span_drift
133 ozonePrecursor_i-Pentane_single_cal_span_actual
134 ozonePrecursor_i-Pentane_single_cal_span_target
135 ozonePrecursor_i-Pentane_single_cal_span_drift
136 ozonePrecursor_n-Pentane_single_cal_span_actual
137 ozonePrecursor_n-Pentane_single_cal_span_target
138 ozonePrecursor_n-Pentane_single_cal_span_drift
139 ozonePrecursor_1_3-Butadiene_single_cal_span_actual
140 ozonePrecursor_1_3-Butadiene_single_cal_span_target
141 ozonePrecursor_1_3-Butadiene_single_cal_span_drift
142 ozonePrecursor_trans-2-Pentene_single_cal_span_actual
143 ozonePrecursor_trans-2-Pentene_single_cal_span_target
144 ozonePrecursor_trans-2-Pentene_single_cal_span_drift
145 ozonePrecursor_1-Pentene_single_cal_span_actual
146 ozonePrecursor_1-Pentene_single_cal_span_target
147 ozonePrecursor_1-Pentene_single_cal_span_drift
148 ozonePrecursor_cis-2-Pentene_single_cal_span_actual
149 ozonePrecursor_cis-2-Pentene_single_cal_span_target
150 ozonePrecursor_cis-2-Pentene_single_cal_span_drift
151 ozonePrecursor_2-Methylpentane_single_cal_span_actual
152 ozonePrecursor_2-Methylpentane_single_cal_span_target
153 ozonePrecursor_2-Methylpentane_single_cal_span_drift
154 ozonePrecursor_n-Hexane(VOC)_single_cal_span_actual
155 ozonePrecursor_n-Hexane(VOC)_single_cal_span_target
156 ozonePrecursor_n-Hexane(VOC)_single_cal_span_drift
157 ozonePrecursor_Isoprene_single_cal_span_actual
158 ozonePrecursor_Isoprene_single_cal_span_target
159 ozonePrecursor_Isoprene_single_cal_span_drift
160 ozonePrecursor_maintenance
161 ozonePrecursor_repair
162 ozone_precursor_flag

View File

@ -0,0 +1,31 @@
so2_so2
so2_so2_daily_Qccheck_zero_actual
so2_so2_daily_Qccheck_zero_target
so2_so2_daily_Qccheck_zero_drift
so2_so2_daily_Qccheck_span_actual
so2_so2_daily_Qccheck_span_target
so2_so2_daily_Qccheck_span_drift
so2_so2_single_cal_zero_actual
so2_so2_single_cal_zero_target
so2_so2_single_cal_zero_drift
so2_so2_single_cal_span_actual
so2_so2_single_cal_span_target
so2_so2_single_cal_span_drift
so2_so2_multi_cal_zero_actual
so2_so2_multi_cal_zero_target
so2_so2_multi_cal_zero_drift
so2_so2_multi_cal_span1_actual
so2_so2_multi_cal_span1_target
so2_so2_multi_cal_span1_drift
so2_so2_multi_cal_span2_actual
so2_so2_multi_cal_span2_target
so2_so2_multi_cal_span2_drift
so2_so2_multi_cal_span3_actual
so2_so2_multi_cal_span3_target
so2_so2_multi_cal_span3_drift
so2_so2_multi_cal_span4_actual
so2_so2_multi_cal_span4_target
so2_so2_multi_cal_span4_drift
so2_maintenance
so2_repair
so2_flag
1 so2_so2
2 so2_so2_daily_Qccheck_zero_actual
3 so2_so2_daily_Qccheck_zero_target
4 so2_so2_daily_Qccheck_zero_drift
5 so2_so2_daily_Qccheck_span_actual
6 so2_so2_daily_Qccheck_span_target
7 so2_so2_daily_Qccheck_span_drift
8 so2_so2_single_cal_zero_actual
9 so2_so2_single_cal_zero_target
10 so2_so2_single_cal_zero_drift
11 so2_so2_single_cal_span_actual
12 so2_so2_single_cal_span_target
13 so2_so2_single_cal_span_drift
14 so2_so2_multi_cal_zero_actual
15 so2_so2_multi_cal_zero_target
16 so2_so2_multi_cal_zero_drift
17 so2_so2_multi_cal_span1_actual
18 so2_so2_multi_cal_span1_target
19 so2_so2_multi_cal_span1_drift
20 so2_so2_multi_cal_span2_actual
21 so2_so2_multi_cal_span2_target
22 so2_so2_multi_cal_span2_drift
23 so2_so2_multi_cal_span3_actual
24 so2_so2_multi_cal_span3_target
25 so2_so2_multi_cal_span3_drift
26 so2_so2_multi_cal_span4_actual
27 so2_so2_multi_cal_span4_target
28 so2_so2_multi_cal_span4_drift
29 so2_maintenance
30 so2_repair
31 so2_flag

View File

@ -0,0 +1,5 @@
teom_teom_a_1-hr_mass_conc
teom_teom_b_1-hr_mass_conc
teom_maintenance
teom_repair
teom_flag
1 teom_teom_a_1-hr_mass_conc
2 teom_teom_b_1-hr_mass_conc
3 teom_maintenance
4 teom_repair
5 teom_flag

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

378
Udara/Demo/Data.json Normal file
View File

@ -0,0 +1,378 @@
{
"Devices": [
{
"DeviceId": 1,
"Code": "42i",
"Name": "nox",
"Mode": "modbus",
"Parameters": {
"NO": "0.910169",
"NO2": "3.80069",
"NOX": "4.71086",
"LO NO": "0",
"INTERNAL TEMP": "32.8056",
"CHAMBER TEMP": "50.1073",
"COOLER TEMP": "-3.04592",
"NO2 CONVERTER TEMP": "326.044",
"CHAMBER PRESSURE": "358.428",
"SAMPLE FLOW": "0.4805",
"PMT VOLTS": "-845.821",
"OZONATOR FLOW": "0.05"
},
"Flags": {
"ZERO MODE": "0",
"SPAN MODE": "0",
"NO MODE": "1",
"NOX MODE": "1",
"INT TEMP ALARM": "0",
"CHAMB TEMP ALARM": "0",
"COOLER TEMP ALARM": "0",
"NO2 CONVERTER TEMP ALARM": "0",
"PERM OVEN GAS TEMP ALARM": "0",
"PRESSURE ALARM": "1",
"FLOW ALARM": "0",
"OZONE FLOW ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0",
"SAMPLE MODE": "0",
"PURGE MODE": "0",
"ZERO CHECK CAL ALARM": "0",
"SPAN CHECK CAL ALARM": "0"
}
},
{
"DeviceId": 2,
"Code": "43i",
"Name": "so2",
"Mode": "modbus",
"Parameters": {
"SO2": "1.97335",
"INTERNAL TEMP": "35.3874",
"CHAMBER TEMP": "44.9375",
"PERM OVEN GAS TEMP": "0",
"PERM OVEN HEATER TEMP": "0",
"CHAMBER PRESSURE": "727.48",
"SAMPLE FLOW": "0.556314",
"PMT VOLTS": "-622.711"
},
"Flags": {
"AUTORANGE": "0",
"LOCAL/REMOTE": "0",
"ZERO MODE": "0",
"SPAN MODE": "0",
"SAMPLE MODE": "0",
"INTERNAL TEMP ALARM": "0",
"CHAMB TEMP ALARM": "0",
"CONVERTER TEMP": "0",
"PERM GAS TEMP": "0",
"PRESSURE ALARM": "0",
"SAMPLE FLOW ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0",
"ZERO CHK CAL ALARM": "0",
"SPAN CHK CAL ALARM": "0"
}
},
{
"DeviceId": 3,
"Code": "48i",
"Name": "co",
"Mode": "modbus",
"Parameters": {
"CO": "302.669",
"INTERNAL TEMP": "35.3874",
"BENCH TEMP": "48.0606",
"PRESSURE": "740.072",
"SAMPLE FLOW": "0.771857",
"INTENSITY": "197009",
"MOTOR SPEED": "100.021"
},
"Flags": {
"ZERO MODE": "0",
"SPAN MODE": "0",
"SAMPLE MODE": "0",
"INTERNAL TEMP ALARM": "0",
"BENCH TEMP ALARM": "0",
"PRESSURE ALARM": "0",
"SAMPLE FLOW ALARM": "0",
"INTENSITY ALARM": "0",
"MOTOR SPEED ALARM": "0",
"BIAS VOLTAGE ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0",
"PURGE MODE": "0",
"ZERO CHK CAL ALARM": "0",
"SPAN CHK CAL ALARM": "0"
}
},
{
"DeviceId": 4,
"Code": "49i",
"Name": "o3",
"Mode": "modbus",
"Parameters": {
"O3": "28.2709",
"INTENSITY A": "48550",
"INTENSITY B": "45101",
"NOISE A": "1.65",
"NOISE B": "1.25",
"FLOW A": "0.747824",
"FLOW B": "0.738708",
"PRESSURE": "739.41",
"BENCH TEMP": "38.5616",
"LAMP TEMP": "53.4734",
"O3 LAMP TEMP": "0"
},
"Flags": {
"ZERO MODE": "0",
"SPAN MODE": "0",
"SAMPLE MODE": "0",
"BENCH TEMP ALARM": "0",
"BENCH LAMP TEMP ALARM": "0",
"PRESSURE ALARM": "0",
"FLOW A ALARM": "0",
"FLOW B ALARM": "0",
"INTENSITY A ALARM": "0",
"INTENSITY B ALARM": "0",
"ZERO CHK CAL ALARM": "0",
"SPAN CHK CAL ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0"
}
},
{
"DeviceId": 5,
"Code": "146i",
"Name": "cal",
"Mode": "modbus",
"Parameters": {
"GAS CONC": "0",
"TARGET GFLOW": "0",
"ACTUAL GFLOW": "0",
"TARGET ZFLOW": "0",
"ACTUAL ZFLOW": "0",
"TARGET TFLOW": "0",
"ACTUAL TFLOW": "0",
"O3 CONC": "0",
"PERM CONC": "0",
"PRESSURE REGISTER": "0",
"BENCH TEMP": "0",
"LAMP TEMP": "0",
"O3 LAMP TEMP REGISTER": "67.9489",
"INTENSITY": "0",
"NOISE": "0",
"ANALOG 1": "0",
"ANALOG 2": "0",
"ANALOG 3": "0",
"ANALOG 4": "0",
"ANALOG 5": "0",
"ANALOG 6": "0",
"ANALOG 7": "0",
"ANALOG 8": "0"
},
"Flags": {
"GAS BIT 1": "0",
"GAS BIT 2": "0",
"GAS BIT 3": "0",
"SPAN BIT 1": "0",
"SPAN BIT 2": "0",
"SPAN BIT 3": "0",
"O3 PERM BIT 1": "0",
"O3 PERM BIT 2": "0",
"O3 PERM BIT 3": "0",
"O3 PERM BIT 4": "0",
"PHOTO BIT 1": "0",
"PHOTO BIT 2": "0",
"GAS A": "0",
"GAS B": "0",
"GAS C": "0",
"GAS D": "0",
"GAS E": "0",
"GAS F": "0",
"OZONATOR": "0",
"PERM OVEN": "0",
"USER 1": "0",
"USER 2": "0",
"USER 3": "0",
"USER 4": "0",
"USER 5": "0",
"USER 6": "0",
"USER 7": "0",
"USER 8": "0",
"GEN ALARM": "0",
"AMBIENT TEMP": "0",
"O3 LAMP TEMP COIL": "0",
"PERM GAS TEMP": "0",
"PRESSURE COIL": "0",
"PHOT BENCH TEMP": "0",
"PHOT LAMP TEMP": "0",
"PHOT INTENSITY": "0",
"O3 LEVEL": "0"
}
},
{
"DeviceId": 6,
"Code": "1405df",
"Name": "teom",
"Mode": "ak",
"Values": {},
"Parameters": {
"System Status": "842137664",
"Case Temperature": "34.243000",
"Cap Temperature": "33.812000",
"Ambient Temperature": "34.027000",
"Ambient Relative Humidity": "66.522003",
"TEOM A Flow Rate": "3.003560",
"TEOM A Flow Volumetric": "3.003560",
"TEOM A Filter Load": "41.659344",
"TEOM A Mass Conc": "-2.006379",
"TEOM A 1-Hr Mass Conc": "19.173367",
"TEOM A Frequency": "260.988328",
"TEOM A Noise": "0.004862",
"TEOM A Dryer Dew Point": "18.719999",
"TEOM A Cooler Temperature": "146.112000",
"TEOM A Base Mass Conc": "-15.170035",
"TEOM A Ref Mass Conc": "-13.163656",
"TEOM B Flow Rate": "1.669940",
"TEOM B Flow Volumetric": "1.669940",
"TEOM B Filter Load": "15.520150",
"TEOM B Mass Conc": "-10.965565",
"TEOM B 1-Hr Mass Conc": "10.450756",
"TEOM B Frequency": "268.335635",
"TEOM B Noise": "0.007932",
"TEOM B Dryer Dew Point": "15.894000",
"TEOM B Cooler Temp": "32.549000",
"TEOM B Base Mass Conc": "-8.474164",
"TEOM B Ref Mass Conc": "2.692038"
}
},
{
"DeviceId": 7,
"Code": "aio",
"Name": "aio2",
"Mode": "serial",
"Values": {},
"Parameters": {
"Wind Speed": "000.9",
"Wind Direction": "162",
"Ambient Temperature": "+033.3",
"Relative Humidity": "065",
"Barometric Pressure": "1008.6",
"Rain": "000.00",
"Solar Radiation": "0226",
"Battery Voltage": "11.6",
"Compass Reading": "203",
"Config": "M0",
"Checksum": "02546"
}
},
{
"DeviceId": 8,
"Code": "ama",
"Name": "ozoneprecursor",
"Mode": "sqlserver",
"Parameters": {
"n-Hexane": "0.484464884950713",
"Benzene": "0.343748092714198",
"2,2,4-Trimethylpentane": "0.0676527332678424",
"n-Heptane": "0",
"Toluene": "0",
"n-Octane": "0.0641648763469244",
"Ethylbenzene": "0.210336043171019",
"m,p-Xylene": "0.374504884378195",
"Styrene": "",
"o-Xylene": "0.188337438788156",
"1,3,5-Trimethylbenzene": "0.127804072300202",
"1,2,4-Trimethylbenzene": "0.124646281832719",
"1,2,3-Trimethylbenzene": "0.0438370534637906",
"Ethane": "0",
"Ethene": "2.29089802244092",
"Propane": "0.932668481496108",
"Propene": "0.288107828566244",
"i-Butane": "0.627011482127217",
"n-Butane": "0.820025435000356",
"Acetylene": "0",
"trans-2-Butene": "0",
"1-Butene": "0",
"cis-2-Butene": "0.775687388214023",
"i-Pentane": "0",
"n-Pentane": "0.485188424420034",
"1,3-Butadiene": "0.501550433804146",
"trans-2-Pentene": "0",
"1-Pentene": "0",
"cis-2-Pentene": "",
"2-Methylpentane": "0.375556231222657",
"n-Hexane(VOC)": "2.34790313544383",
"Isoprene": "1.82749462737622"
},
"Flags": {}
},
{
"DeviceId": 9,
"Code": "trace1600",
"Name": "ozoneprecursor",
"Mode": "csv",
"Parameters": {
"RT_n-Hexane": "6.53",
"Conc_n-Hexane": "0.2885",
"RT_Benzene": "8.01",
"Conc_Benzene": "1.9816",
"RT_2.2.4-Trimethylpentene": "9.09",
"Conc_2.2.4-Trimethylpentene": "0.1475",
"RT_n-Heptane": "9.09",
"Conc_n-Heptane": "0.4461",
"RT_Toluene": "11.26",
"Conc_Toluene": "7.3416",
"RT_n-Octane": "12.56",
"Conc_n-Octane": "0.1128",
"RT_Ethylbenzene": "14.28",
"Conc_Ethylbenzene": "1.1071",
"RT_p/m-Xylene": "14.52",
"Conc_p/m-Xylene": "2.3680",
"RT_o-Xylene": "15.21",
"Conc_o-Xylene": "0.8644",
"RT_1.3.5-Trimethylbenzene": "17.18",
"Conc_1.3.5-Trimethylbenzene": "0.1939",
"RT_1.2.4-Trimethylbenzene": "17.81",
"Conc_1.2.4-Trimethylbenzene": "0.5433",
"RT_1.2.3-Trimethylbenzene": "18.49",
"Conc_1.2.3-Trimethylbenzene": "0.1672",
"RT_Ethane": "5.41",
"Conc_Ethane": "4.6423",
"RT_Ethene": "5.77",
"Conc_Ethene": "5.1753",
"RT_Propane": "6.67",
"Conc_Propane": "20.4921",
"RT_Propene": "8.72",
"Conc_Propene": "2.0739",
"RT_i-Butane": "9.68",
"Conc_i-Butane": "13.6268",
"RT_n-Butane": "10.17",
"Conc_n-Butane": "17.2023",
"RT_Acetylene": "10.54",
"Conc_Acetylene": "4.1668",
"RT_Trans-2-Butane": "12.68",
"Conc_Trans-2-Butane": "0.5570",
"RT_1-Butene": "12.92",
"Conc_1-Butene": "0.9296",
"RT_cis-2-Butene": "13.71",
"Conc_cis-2-Butene": "0.4130",
"RT_i-Pentane": "14.26",
"Conc_i-Pentane": "9.8822",
"RT_n-Pentane": "14.74",
"Conc_n-Pentane": "5.4647",
"RT_1.3-Butadiene": "15.31",
"Conc_1.3-Butadiene": "0.6577",
"RT_Trans-2-Pentene": "16.38",
"Conc_Trans-2-Pentene": "0.3918",
"RT_1-Pentene": "16.84",
"Conc_1-Pentene": "0.1332",
"RT_2-Methylpentane": "18.00",
"Conc_2-Methylpentane": "2.1133",
"RT_IsoPrene": "18.82",
"Conc_IsoPrene": "0.1381"
},
"Flags": {}
}
]
}

10
Udara/Demo/M01-101.txt Normal file
View File

@ -0,0 +1,10 @@
172.16.101.42
172.16.101.42
172.16.101.43
172.16.101.43
172.16.101.48
172.16.101.48
172.16.101.49
172.16.101.49
172.16.101.146
172.16.101.146

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

322
Udara/Demo/OldData.json Normal file
View File

@ -0,0 +1,322 @@
{
"Devices": [
{
"DeviceId": 1,
"Code": "42i",
"Name": "nox",
"Mode": "modbus",
"Values": {
"coils": {
"ZERO MODE": "0",
"SPAN MODE": "0",
"NO MODE": "1",
"NOX MODE": "1",
"INT TEMP ALARM": "0",
"CHAMB TEMP ALARM": "0",
"COOLER TEMP ALARM": "0",
"NO2 CONVERTER TEMP ALARM": "0",
"PERM OVEN GAS TEMP ALARM": "0",
"PRESSURE ALARM": "0",
"FLOW ALARM": "0",
"OZONE FLOW ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0",
"SAMPLE MODE": "0",
"PURGE MODE": "0",
"ZERO CHECK CAL ALARM": "0",
"SPAN CHECK CAL ALARM": "0"
},
"registers": {
"NO": "52.5286",
"NO2": "23.4154",
"NOX": "75.944",
"LO NO": "0",
"INTERNAL TEMP": "35.1565",
"CHAMBER TEMP": "50.1073",
"COOLER TEMP": "-2.86198",
"NO2 CONVERTER TEMP": "322.631",
"CHAMBER PRESSURE": "259.936",
"SAMPLE FLOW": "0.695768",
"PMT VOLTS": "-846.191",
"OZONATOR FLOW": "0.05"
}
}
},
{
"DeviceId": 2,
"Code": "43i",
"Name": "so2",
"Mode": "modbus",
"Values": {
"coils": {
"AUTORANGE": "0",
"LOCAL/REMOTE": "0",
"ZERO MODE": "0",
"SPAN MODE": "0",
"SAMPLE MODE": "0",
"INTERNAL TEMP ALARM": "0",
"CHAMB TEMP ALARM": "0",
"CONVERTER TEMP": "0",
"PERM GAS TEMP": "0",
"PRESSURE ALARM": "0",
"SAMPLE FLOW ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0",
"ZERO CHK CAL ALARM": "0",
"SPAN CHK CAL ALARM": "0"
},
"registers": {
"SO2": "0.965215",
"INTERNAL TEMP": "37.2088",
"CHAMBER TEMP": "45.0619",
"PERM OVEN GAS TEMP": "0",
"PERM OVEN HEATER TEMP": "0",
"CHAMBER PRESSURE": "731.395",
"SAMPLE FLOW": "0.558697",
"PMT VOLTS": "-622.711"
}
}
},
{
"DeviceId": 3,
"Code": "48i",
"Name": "co",
"Mode": "modbus",
"Values": {
"coils": {
"ZERO MODE": "0",
"SPAN MODE": "0",
"SAMPLE MODE": "0",
"INTERNAL TEMP ALARM": "0",
"BENCH TEMP ALARM": "0",
"PRESSURE ALARM": "0",
"SAMPLE FLOW ALARM": "0",
"INTENSITY ALARM": "0",
"MOTOR SPEED ALARM": "0",
"BIAS VOLTAGE ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0",
"PURGE MODE": "0",
"ZERO CHK CAL ALARM": "0",
"SPAN CHK CAL ALARM": "0"
},
"registers": {
"CO": "1330.53",
"INTERNAL TEMP": "37.6449",
"BENCH TEMP": "47.9628",
"PRESSURE": "743.735",
"SAMPLE FLOW": "0.769839",
"INTENSITY": "196445",
"MOTOR SPEED": "100.03"
}
}
},
{
"DeviceId": 4,
"Code": "49i",
"Name": "o3",
"Mode": "modbus",
"Values": {
"coils": {
"ZERO MODE": "0",
"SPAN MODE": "0",
"SAMPLE MODE": "0",
"BENCH TEMP ALARM": "0",
"BENCH LAMP TEMP ALARM": "0",
"PRESSURE ALARM": "0",
"FLOW A ALARM": "0",
"FLOW B ALARM": "0",
"INTENSITY A ALARM": "0",
"INTENSITY B ALARM": "0",
"ZERO CHK CAL ALARM": "0",
"SPAN CHK CAL ALARM": "0",
"MOTHERBOARD STATUS ALARM": "0",
"INTERFACE BD STATUS ALARM": "0"
},
"registers": {
"O3": "2.19913",
"INTENSITY A": "51131",
"INTENSITY B": "46722",
"NOISE A": "0.4",
"NOISE B": "0.5",
"FLOW A": "0.742515",
"FLOW B": "0.748315",
"PRESSURE": "743.022",
"BENCH TEMP": "37.9565",
"LAMP TEMP": "53.3333",
"O3 LAMP TEMP": "0"
}
}
},
{
"DeviceId": 5,
"Code": "146i",
"Name": "cal",
"Mode": "modbus",
"Values": {
"coils": {
"GAS BIT 1": "0",
"GAS BIT 2": "0",
"GAS BIT 3": "0",
"SPAN BIT 1": "0",
"SPAN BIT 2": "0",
"SPAN BIT 3": "0",
"O3 PERM BIT 1": "0",
"O3 PERM BIT 2": "0",
"O3 PERM BIT 3": "0",
"O3 PERM BIT 4": "0",
"PHOTO BIT 1": "0",
"PHOTO BIT 2": "0",
"GAS A": "0",
"GAS B": "0",
"GAS C": "0",
"GAS D": "0",
"GAS E": "0",
"GAS F": "0",
"OZONATOR": "0",
"PERM OVEN": "0",
"USER 1": "0",
"USER 2": "0",
"USER 3": "0",
"USER 4": "0",
"USER 5": "0",
"USER 6": "0",
"USER 7": "0",
"USER 8": "0",
"GEN ALARM": "0",
"AMBIENT TEMP": "0",
"O3 LAMP TEMP COIL": "0",
"PERM GAS TEMP": "0",
"PRESSURE COIL": "0",
"PHOT BENCH TEMP": "0",
"PHOT LAMP TEMP": "0",
"PHOT INTENSITY": "0",
"O3 LEVEL": "0"
},
"registers": {
"GAS CONC": "0",
"TARGET GFLOW": "0",
"ACTUAL GFLOW": "0",
"TARGET ZFLOW": "0",
"ACTUAL ZFLOW": "0",
"TARGET TFLOW": "0",
"ACTUAL TFLOW": "0",
"O3 CONC": "0",
"PERM CONC": "0",
"PRESSURE REGISTER": "0",
"BENCH TEMP": "0",
"LAMP TEMP": "0",
"O3 LAMP TEMP REGISTER": "67.8798",
"INTENSITY": "0",
"NOISE": "0",
"ANALOG 1": "0",
"ANALOG 2": "0",
"ANALOG 3": "0",
"ANALOG 4": "0",
"ANALOG 5": "0",
"ANALOG 6": "0",
"ANALOG 7": "0",
"ANALOG 8": "0"
}
}
},
{
"DeviceId": 6,
"Code": "1405df",
"Name": "teom",
"Mode": "ak",
"Values": {
"registers": {
"System Status": "842137664",
"Case Temperature": "34.138000",
"Cap Temperature": "33.563000",
"Ambient Temperature": "24.423000",
"Ambient Relative Humidity": "98.226997",
"TEOM A Flow Rate": "3.001083",
"TEOM A Flow Volumetric": "3.001083",
"TEOM A Filter Load": "58.404751",
"TEOM A Mass Conc": "40.651314",
"TEOM A 1-Hr Mass Conc": "42.717293",
"TEOM A Frequency": "260.737398",
"TEOM A Noise": "0.003009",
"TEOM A Dryer Dew Point": "18.059000",
"TEOM A Cooler Temperature": "156.656998",
"TEOM A Base Mass Conc": "35.894749",
"TEOM A Ref Mass Conc": "-4.756568",
"TEOM B Flow Rate": "1.673967",
"TEOM B Flow Volumetric": "1.673967",
"TEOM B Filter Load": "14.703300",
"TEOM B Mass Conc": "22.502310",
"TEOM B 1-Hr Mass Conc": "20.611660",
"TEOM B Frequency": "269.810451",
"TEOM B Noise": "0.008147",
"TEOM B Dryer Dew Point": "15.092000",
"TEOM B Cooler Temp": "31.298000",
"TEOM B Base Mass Conc": "17.669052",
"TEOM B Ref Mass Conc": "-8.898390"
}
}
},
{
"DeviceId": 7,
"Code": "aio",
"Name": "aio2",
"Mode": "serial",
"Values": {
"registers": {
"Wind Speed": "001.2",
"Wind Direction": "078",
"Ambient Temperature": "+024.4",
"Relative Humidity": "094",
"Barometric Pressure": "1012.2",
"Rain": "000.00",
"Solar Radiation": "0000",
"Battery Voltage": "11.6",
"Compass Reading": "204",
"Config": "M0",
"Checksum": "02531"
}
}
},
{
"DeviceId": 8,
"Code": "ama",
"Name": "ozoneprecursor",
"Mode": "sqlserver",
"Values": {
"records": {
"n-Hexane": "1.90965914981543",
"Benzene": "3.15450421427172",
"2,2,4-Trimethylpentane": "0.326820302007518",
"n-Heptane": "0.462037380914552",
"Toluene": "5.54570154009161",
"n-Octane": "0.232242532762861",
"Ethylbenzene": "1.36736475370466",
"m,p-Xylene": "4.17614576951828",
"o-Xylene": "1.54728054065554",
"1,3,5-Trimethylbenzene": "0.954729491048662",
"1,2,4-Trimethylbenzene": "0.0778578459822015",
"1,2,3-Trimethylbenzene": "0.684891626947891",
"Ethane": "751.839941139116",
"Propane": "11.4367498915847",
"Propene": "3.20627189267601",
"n-Butane": "9.03891848210978",
"Acetylene": "8.596369796437",
"trans-2-Butene": "0.487337419423999",
"cis-2-Butene": "6.12328662491597",
"n-Pentane": "4.55600328780163",
"1,3-Butadiene": "1.00341345168309",
"trans-2-Pentene": "0.270654051057631",
"1-Pentene": "0.441963118668669",
"2-Methylpentane": "4.4342083089133",
"n-Hexane(VOC)": "2.93893273212621",
"Isoprene": "0.720918286820498",
"Ethene": "0",
"i-Butane": "0",
"1-Butene": "0",
"i-Pentane": "0"
}
}
}
]
}

10
Udara/Demo/S24-24.txt Normal file
View File

@ -0,0 +1,10 @@
172.16.24.42
172.16.24.42
172.16.24.43
172.16.24.43
172.16.24.48
172.16.24.48
172.16.24.49
172.16.24.49
172.16.24.146
172.16.24.146

30
Udara/Demo/Teom.csv Normal file
View File

@ -0,0 +1,30 @@
teom_a_base_mass_conc,TEOM A Base Mass Conc,,,,,,,,,,,,System Status
teom_a_cooler_temperature,TEOM A Cooler Temperature,,,,,,,,,,,,
teom_a_ref_mass_conc,TEOM A Ref Mass Conc,,,,,,,,,,,,
teom_ambient_relative_humidity,Ambient Relative Humidity,,,,,,,,,,,,
teom_ambient_temperature,Ambient Temperature,,,,,,,,,,,,
teom_b_base_mass_conc,TEOM B Base Mass Conc,,,,,,,,,,,,TEOM A Flow Rate
teom_b_cooler_temp,TEOM B Cooler Temp,,,,,,,,,,,,TEOM A Flow Volumetric
teom_b_ref_mass_conc,TEOM B Ref Mass Conc,,,,,,,,,,,,
teom_cap_temperature,Cap Temperature,,,,,,,,,,,,TEOM A Mass Conc
teom_case_temperature,Case Temperature,,,,,,,,,,,,
teom_flag,,,,,,,,,,,,,TEOM A Frequency
teom_maintenance,,,,,,,,,,,,,TEOM A Noise
teom_repair,,,,,,,,,,,,,
teom_system_status,,,,,,,,,,,,,
teom_teom_a_1-hr_mass_conc,TEOM A 1-Hr Mass Conc,,,,,,,,,,,,
teom_teom_a_1-hr_mass_conc,,,,,,,,,,,,,
teom_teom_a_dryer_dew,TEOM A Dryer Dew Point,,,,,,,,,,,,TEOM B Flow Rate
teom_teom_a_filter_load,TEOM A Filter Load,,,,,,,,,,,,TEOM B Flow Volumetric
teom_teom_a_flow_rate,,,,,,,,,,,,,TEOM B Filter Load
teom_teom_a_flow_volumetric,,,,,,,,,,,,,TEOM B Mass Conc
teom_teom_a_frequency,,,,,,,,,,,,,TEOM B 1-Hr Mass Conc
teom_teom_a_noise,,,,,,,,,,,,,TEOM B Frequency
teom_teom_b_1-hr_mass_conc,,,,,,,,,,,,,TEOM B Noise
teom_teom_b_1-hr_mass_conc,,,,,,,,,,,,,TEOM B Dryer Dew Point
teom_teom_b_dryer_dew,,,,,,,,,,,,,
teom_teom_b_filter_load,,,,,,,,,,,,,
teom_teom_b_flow_rate,,,,,,,,,,,,,
teom_teom_b_flow_volumetric,,,,,,,,,,,,,
teom_teom_b_frequency,,,,,,,,,,,,,
teom_teom_b_noise,,,,,,,,,,,,,
1 teom_a_base_mass_conc TEOM A Base Mass Conc System Status
2 teom_a_cooler_temperature TEOM A Cooler Temperature
3 teom_a_ref_mass_conc TEOM A Ref Mass Conc
4 teom_ambient_relative_humidity Ambient Relative Humidity
5 teom_ambient_temperature Ambient Temperature
6 teom_b_base_mass_conc TEOM B Base Mass Conc TEOM A Flow Rate
7 teom_b_cooler_temp TEOM B Cooler Temp TEOM A Flow Volumetric
8 teom_b_ref_mass_conc TEOM B Ref Mass Conc
9 teom_cap_temperature Cap Temperature TEOM A Mass Conc
10 teom_case_temperature Case Temperature
11 teom_flag TEOM A Frequency
12 teom_maintenance TEOM A Noise
13 teom_repair
14 teom_system_status
15 teom_teom_a_1-hr_mass_conc TEOM A 1-Hr Mass Conc
16 teom_teom_a_1-hr_mass_conc
17 teom_teom_a_dryer_dew TEOM A Dryer Dew Point TEOM B Flow Rate
18 teom_teom_a_filter_load TEOM A Filter Load TEOM B Flow Volumetric
19 teom_teom_a_flow_rate TEOM B Filter Load
20 teom_teom_a_flow_volumetric TEOM B Mass Conc
21 teom_teom_a_frequency TEOM B 1-Hr Mass Conc
22 teom_teom_a_noise TEOM B Frequency
23 teom_teom_b_1-hr_mass_conc TEOM B Noise
24 teom_teom_b_1-hr_mass_conc TEOM B Dryer Dew Point
25 teom_teom_b_dryer_dew
26 teom_teom_b_filter_load
27 teom_teom_b_flow_rate
28 teom_teom_b_flow_volumetric
29 teom_teom_b_frequency
30 teom_teom_b_noise

541
Udara/Demo/a.txt Normal file
View File

@ -0,0 +1,541 @@
Record Date
Station
teom_case_temperature
teom_cap_temperature
teom_ambient_temperature
teom_ambient_relative_humidity
teom_teom_a_flow_rate
teom_teom_a_flow_volumetric
teom_teom_a_filter_load
teom_teom_a_1-hr_mass_conc
teom_teom_a_1-hr_mass_conc
teom_teom_a_frequency
teom_teom_a_noise
teom_teom_b_flow_rate
teom_teom_b_flow_volumetric
teom_teom_b_filter_load
teom_teom_b_1-hr_mass_conc
teom_teom_b_1-hr_mass_conc
teom_teom_b_frequency
teom_teom_b_noise
teom_system_status
nox_zero_mode
nox_span_mode
nox_no_mode
nox_nox_mode
nox_int_temp_alarm
nox_chamb_temp_alarm
nox_cooler_temp_alarm
nox_no2_converter_temp_alarm
nox_perm_oven_gas_temp_alarm
nox_pressure_alarm
nox_flow_alarm
nox_ozone_flow_alarm
nox_motherboard_status_alarm
nox_interface_bd_status_alarm
nox_sample_mode
nox_purge_mode
nox_zero_check_cal_alarm
nox_span_check_cal_alarm
nox_no
nox_no2
nox_nox
nox_internal_temp
nox_chamber_temp
nox_cooler_temp
nox_no2_converter_temp
nox_chamber_pressure
nox_sample_flow
nox_pmt_volts
nox_ozonator_flow
so2_autorange
so2_local/remote
so2_zero_mode
so2_span_mode
so2_sample_mode
so2_internal_temp_alarm
so2_chamb_temp_alarm
so2_converter_temp
so2_perm_gas_temp
so2_pressure_alarm
so2_sample_flow_alarm
so2_motherboard_status_alarm
so2_interface_bd_status_alarm
so2_zero_chk_cal_alarm
so2_span_chk_cal_alarm
so2_so2
so2_internal_temp
so2_chamber_temp
so2_perm_oven_gas_temp
so2_perm_oven_heater_temp
so2_chamber_pressure
so2_sample_flow
so2_pmt_volts
co_zero_mode
co_span_mode
co_sample_mode
co_internal_temp_alarm
co_bench_temp_alarm
co_pressure_alarm
co_sample_flow_alarm
co_intensity_alarm
co_motor_speed_alarm
co_bias_voltage_alarm
co_motherboard_status_alarm
co_interface_bd_status_alarm
co_purge_mode
co_zero_chk_cal_alarm
co_span_chk_cal_alarm
co_co
co_internal_temp
co_bench_temp
co_pressure
co_sample_flow
co_intensity
co_motor_speed
o3_zero_mode
o3_span_mode
o3_sample_mode
o3_bench_temp_alarm
o3_bench_lamp_temp_alarm
o3_pressure_alarm
o3_flow_a_alarm
o3_flow_b_alarm
o3_intensity_a_alarm
o3_intensity_b_alarm
o3_zero_chk_cal_alarm
o3_span_chk_cal_alarm
o3_motherboard_status_alarm
o3_interface_bd_status_alarm
o3_o3
o3_intensity_a
o3_intensity_b
o3_noise_a
o3_noise_b
o3_flow_a
o3_flow_b
o3_pressure
o3_bench_temp
o3_lamp_temp
o3_o3_lamp_temp
cal_gas_bit_1
cal_gas_bit_2
cal_gas_bit_3
cal_span_bit_1
cal_span_bit_2
cal_span_bit_3
cal_o3_perm_bit_1
cal_o3_perm_bit_2
cal_o3_perm_bit_3
cal_o3_perm_bit_4
cal_photo_bit_2
cal_photo_bit_1
cal_gas_a
cal_gas_b
cal_gas_c
cal_gas_d
cal_gas_e
cal_gas_f
cal_ozonator
cal_perm_oven
cal_user_1
cal_user_2
cal_user_3
cal_user_4
cal_user_5
cal_user_6
cal_user_7
cal_user_8
cal_gen_alarm
cal_ambient_temp
cal_o3_lamp_temp_coil
cal_perm_gas_temp
cal_pressure_coil
cal_phot_bench_temp
cal_phot_lamp_temp
cal_phot_intensity
cal_o3_level
cal_gas_conc
cal_target_gflow
cal_actual_gflow
cal_target_zflow
cal_actual_zflow
cal_target_tflow
cal_actual_tflow
cal_o3_conc
cal_perm_conc
cal_pressure_register
cal_bench_temp
cal_lamp_temp
cal_o3_lamp_temp_register
cal_intensity
cal_noise
cal_analog_1
cal_analog_2
cal_analog_3
cal_analog_4
cal_analog_5
cal_analog_6
cal_analog_7
cal_analog_8
ozonePrecursor_n-Hexane
ozonePrecursor_Benzene
ozonePrecursor_2_2_4-Trimethylpentane
ozonePrecursor_n-Heptane
ozonePrecursor_Toluene
ozonePrecursor_n-Octane
ozonePrecursor_Ethylbenzene
ozonePrecursor_m_p-Xylene
??ozonePrecursor_Styrene
ozonePrecursor_o-Xylene
ozonePrecursor_1_3_5-Trimethylbenzene
ozonePrecursor_1_2_4-Trimethylbenzene
ozonePrecursor_1_2_3-Trimethylbenzene
ozonePrecursor_Ethane
ozonePrecursor_Ethene
ozonePrecursor_Propane
ozonePrecursor_Propene
ozonePrecursor_i-Butane
ozonePrecursor_n-Butane
ozonePrecursor_Acetylene
ozonePrecursor_trans-2-Butene
ozonePrecursor_1-Butene
ozonePrecursor_cis-2-Butene
ozonePrecursor_i-Pentane
ozonePrecursor_n-Pentane
ozonePrecursor_1_3-Butadiene
ozonePrecursor_trans-2-Pentene
ozonePrecursor_1-Pentene
??ozonePrecursor_cis-2-Pentene
ozonePrecursor_2-Methylpentane
ozonePrecursor_n-Hexane(VOC)
ozonePrecursor_Isoprene
aio_wind_speed
aio_wind_direction
aio_ambient_temperature
aio_relative_humidity
aio_baromatric_pressure
aio_rain
aio_solar_radiation
aio_CONFIG
aio_battery_voltage
nox_no_daily_Qccheck_zero_actual
nox_no_daily_Qccheck_zero_target
nox_no_daily_Qccheck_zero_drift
nox_no_daily_Qccheck_span_actual
nox_no_daily_Qccheck_span_target
nox_no_daily_Qccheck_span_drift
nox_no2_daily_Qccheck_zero_target
nox_no2_daily_Qccheck_zero_actual
nox_no2_daily_Qccheck_zero_drift
nox_no2_daily_Qccheck_span_actual
nox_no2_daily_Qccheck_span_target
nox_no2_daily_Qccheck_span_drift
nox_nox_daily_Qccheck_zero_actual
nox_nox_daily_Qccheck_zero_target
nox_nox_daily_Qccheck_zero_drift
nox_nox_daily_Qccheck_span_actual
nox_nox_daily_Qccheck_span_target
nox_nox_daily_Qccheck_span_drift
so2_so2_daily_Qccheck_zero_actual
so2_so2_daily_Qccheck_zero_target
so2_so2_daily_Qccheck_zero_drift
so2_so2_daily_Qccheck_span_actual
so2_so2_daily_Qccheck_span_target
so2_so2_daily_Qccheck_span_drift
co_co_daily_Qccheck_zero_actual
co_co_daily_Qccheck_zero_target
co_co_daily_Qccheck_zero_drift
co_co_daily_Qccheck_span_actual
co_co_daily_Qccheck_span_target
co_co_daily_Qccheck_span_drift
o3_o3_daily_Qccheck_zero_actual
o3_o3_daily_Qccheck_zero_target
o3_o3_daily_Qccheck_zero_drift
o3_o3_daily_Qccheck_span_actual
o3_o3_daily_Qccheck_span_target
o3_o3_daily_Qccheck_span_drift
ozonePrecursor_n-Hexane_daily_Qccheck_span_drift
ozonePrecursor_Benzene_daily_Qccheck_span_drift
ozonePrecursor_2_2_4-Trimethylpentane_daily_Qccheck_span_drift
ozonePrecursor_n-Heptane_daily_Qccheck_span_drift
ozonePrecursor_Toluene_daily_Qccheck_span_drift
ozonePrecursor_n-Octane_daily_Qccheck_span_drift
ozonePrecursor_Ethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_m_p-Xylene_daily_Qccheck_span_drift
ozonePrecursor_Styrene_daily_Qccheck_span_drift
ozonePrecursor_o-Xylene_daily_Qccheck_span_drift
ozonePrecursor_1_3_5-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_1_2_4-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_1_2_3-Trimethylbenzene_daily_Qccheck_span_drift
ozonePrecursor_Ethane_daily_Qccheck_span_drift
ozonePrecursor_Ethene_daily_Qccheck_span_drift
ozonePrecursor_Propane_daily_Qccheck_span_drift
ozonePrecursor_Propene_daily_Qccheck_span_drift
ozonePrecursor_i-Butane_daily_Qccheck_span_drift
ozonePrecursor_n-Butane_daily_Qccheck_span_drift
ozonePrecursor_Acetylene_daily_Qccheck_span_drift
ozonePrecursor_trans-2-Butene_daily_Qccheck_span_drift
ozonePrecursor_1-Butene_daily_Qccheck_span_drift
ozonePrecursor_cis-2-Butene_daily_Qccheck_span_drift
ozonePrecursor_i-Pentane_daily_Qccheck_span_drift
ozonePrecursor_n-Pentane_daily_Qccheck_span_drift
ozonePrecursor_1_3-Butadiene_daily_Qccheck_span_drift
ozonePrecursor_trans-2-Pentene_daily_Qccheck_span_drift
ozonePrecursor_cis-2-Pentene_daily_Qccheck_span_drift
ozonePrecursor_2-Methylpentane_daily_Qccheck_span_drift
ozonePrecursor_n-Hexane(VOC)_daily_Qccheck_span_drift
ozonePrecursor_Isoprene_daily_Qccheck_span_drift
nox_no_single_cal_zero_actual
nox_no_single_cal_zero_target
nox_no_single_cal_zero_drift
nox_no_single_cal_span_actual
nox_no_single_cal_span_target
nox_no_single_cal_span_drift
nox_no2_single_cal_zero_actual
nox_no2_single_cal_zero_target
nox_no2_single_cal_zero_drift
nox_no2_single_cal_span_actual
nox_no2_single_cal_span_target
nox_no2_single_cal_span_drift
nox_nox_single_cal_zero_actual
nox_nox_single_cal_zero_target
nox_nox_single_cal_zero_drift
nox_nox_single_cal_span_actual
nox_nox_single_cal_span_target
nox_nox_single_cal_span_drift
so2_so2_single_cal_zero_actual
so2_so2_single_cal_zero_target
so2_so2_single_cal_zero_drift
so2_so2_single_cal_span_actual
so2_so2_single_cal_span_target
so2_so2_single_cal_span_drift
co_co_single_cal_zero_actual
co_co_single_cal_zero_target
co_co_single_cal_zero_drift
co_co_single_cal_span_actual
co_co_single_cal_span_target
co_co_single_cal_span_drift
o3_o3_single_cal_zero_actual
o3_o3_single_cal_zero_target
o3_o3_single_cal_zero_drift
o3_o3_single_cal_span_actual
o3_o3_single_cal_span_target
o3_o3_single_cal_span_drift
nox_no_multi_cal_zero_actual
nox_no_multi_cal_zero_target
nox_no_multi_cal_zero_drift
nox_no_multi_cal_span1_actual
nox_no_multi_cal_span1_target
nox_no_multi_cal_span1_drift
nox_no_multi_cal_span2_actual
nox_no_multi_cal_span2_target
nox_no_multi_cal_span2_drift
nox_no_multi_cal_span3_actual
nox_no_multi_cal_span3_target
nox_no_multi_cal_span3_drift
nox_no_multi_cal_span4_actual
nox_no_multi_cal_span4_target
nox_no_multi_cal_span4_drift
nox_no2_multi_cal_zero_actual
nox_no2_multi_cal_zero_target
nox_no2_multi_cal_zero_drift
nox_no2_multi_cal_span1_actual
nox_no2_multi_cal_span1_target
nox_no2_multi_cal_span1_drift
nox_no2_multi_cal_span2_actual
nox_no2_multi_cal_span2_target
nox_no2_multi_cal_span2_drift
nox_no2_multi_cal_span3_actual
nox_no2_multi_cal_span3_target
nox_no2_multi_cal_span3_drift
nox_no2_multi_cal_span4_actual
nox_no2_multi_cal_span4_target
nox_no2_multi_cal_span4_drift
nox_nox_multi_cal_zero_actual
nox_nox_multi_cal_zero_target
nox_nox_multi_cal_zero_drift
nox_nox_multi_cal_span1_actual
nox_nox_multi_cal_span1_target
nox_nox_multi_cal_span1_drift
nox_nox_multi_cal_span2_actual
nox_nox_multi_cal_span2_target
nox_nox_multi_cal_span2_drift
nox_nox_multi_cal_span3_actual
nox_nox_multi_cal_span3_target
nox_nox_multi_cal_span3_drift
nox_nox_multi_cal_span4_actual
nox_nox_multi_cal_span4_target
nox_nox_multi_cal_span4_drift
so2_so2_multi_cal_zero_actual
so2_so2_multi_cal_zero_target
so2_so2_multi_cal_zero_drift
so2_so2_multi_cal_span1_actual
so2_so2_multi_cal_span1_target
so2_so2_multi_cal_span1_drift
so2_so2_multi_cal_span2_actual
so2_so2_multi_cal_span2_target
so2_so2_multi_cal_span2_drift
so2_so2_multi_cal_span3_actual
so2_so2_multi_cal_span3_target
so2_so2_multi_cal_span3_drift
so2_so2_multi_cal_span4_actual
so2_so2_multi_cal_span4_target
so2_so2_multi_cal_span4_drift
co_co_multi_cal_zero_actual
co_co_multi_cal_zero_target
co_co_multi_cal_zero_drift
co_co_multi_cal_span1_actual
co_co_multi_cal_span1_target
co_co_multi_cal_span1_drift
co_co_multi_cal_span2_actual
co_co_multi_cal_span2_target
co_co_multi_cal_span2_drift
co_co_multi_cal_span3_actual
co_co_multi_cal_span3_target
co_co_multi_cal_span3_drift
co_co_multi_cal_span4_actual
co_co_multi_cal_span4_target
co_co_multi_cal_span4_drift
o3_o3_multi_cal_zero_actual
o3_o3_multi_cal_zero_target
o3_o3_multi_cal_zero_drift
o3_o3_multi_cal_span1_actual
o3_o3_multi_cal_span1_target
o3_o3_multi_cal_span1_drift
o3_o3_multi_cal_span2_actual
o3_o3_multi_cal_span2_target
o3_o3_multi_cal_span2_drift
o3_o3_multi_cal_span3_actual
o3_o3_multi_cal_span3_target
o3_o3_multi_cal_span3_drift
o3_o3_multi_cal_span4_actual
o3_o3_multi_cal_span4_target
o3_o3_multi_cal_span4_drift
ozonePrecursor_n-Hexane_single_cal_span_actual
ozonePrecursor_n-Hexane_single_cal_span_target
ozonePrecursor_n-Hexane_single_cal_span_drift
ozonePrecursor_Benzene_single_cal_span_actual
ozonePrecursor_Benzene_single_cal_span_target
ozonePrecursor_Benzene_single_cal_span_drift
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_actual
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_target
ozonePrecursor_2_2_4-Trimethylpentane_single_cal_span_drift
ozonePrecursor_n-Heptane_single_cal_span_actual
ozonePrecursor_n-Heptane_single_cal_span_target
ozonePrecursor_n-Heptane_single_cal_span_drift
ozonePrecursor_Toluene_single_cal_span_actual
ozonePrecursor_Toluene_single_cal_span_target
ozonePrecursor_Toluene_single_cal_span_drift
ozonePrecursor_n-Octane_single_cal_span_actual
ozonePrecursor_n-Octane_single_cal_span_target
ozonePrecursor_n-Octane_single_cal_span_drift
ozonePrecursor_Ethylbenzene_single_cal_span_actual
ozonePrecursor_Ethylbenzene_single_cal_span_target
ozonePrecursor_Ethylbenzene_single_cal_span_drift
ozonePrecursor_m_p-Xylene_single_cal_span_actual
ozonePrecursor_m_p-Xylene_single_cal_span_target
ozonePrecursor_m_p-Xylene_single_cal_span_drift
ozonePrecursor_Styrene_single_cal_span_actual
ozonePrecursor_Styrene_single_cal_span_target
ozonePrecursor_Styrene_single_cal_span_drift
ozonePrecursor_o-Xylene_single_cal_span_actual
ozonePrecursor_o-Xylene_single_cal_span_target
ozonePrecursor_o-Xylene_single_cal_span_drift
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_3_5-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_2_4-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_actual
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_target
ozonePrecursor_1_2_3-Trimethylbenzene_single_cal_span_drift
ozonePrecursor_Ethane_single_cal_span_actual
ozonePrecursor_Ethane_single_cal_span_target
ozonePrecursor_Ethane_single_cal_span_drift
ozonePrecursor_Ethene_single_cal_span_actual
ozonePrecursor_Ethene_single_cal_span_target
ozonePrecursor_Ethene_single_cal_span_drift
ozonePrecursor_Propane_single_cal_span_actual
ozonePrecursor_Propane_single_cal_span_target
ozonePrecursor_Propane_single_cal_span_drift
ozonePrecursor_Propene_single_cal_span_actual
ozonePrecursor_Propene_single_cal_span_target
ozonePrecursor_Propene_single_cal_span_drift
ozonePrecursor_i-Butane_single_cal_span_actual
ozonePrecursor_i-Butane_single_cal_span_target
ozonePrecursor_i-Butane_single_cal_span_drift
ozonePrecursor_n-Butane_single_cal_span_actual
ozonePrecursor_n-Butane_single_cal_span_target
ozonePrecursor_n-Butane_single_cal_span_drift
ozonePrecursor_Acetylene_single_cal_span_actual
ozonePrecursor_Acetylene_single_cal_span_target
ozonePrecursor_Acetylene_single_cal_span_drift
ozonePrecursor_trans-2-Butene_single_cal_span_actual
ozonePrecursor_trans-2-Butene_single_cal_span_target
ozonePrecursor_trans-2-Butene_single_cal_span_drift
ozonePrecursor_1-Butene_single_cal_span_actual
ozonePrecursor_1-Butene_single_cal_span_target
ozonePrecursor_1-Butene_single_cal_span_drift
ozonePrecursor_cis-2-Butene_single_cal_span_actual
ozonePrecursor_cis-2-Butene_single_cal_span_target
ozonePrecursor_cis-2-Butene_single_cal_span_drift
ozonePrecursor_i-Pentane_single_cal_span_actual
ozonePrecursor_i-Pentane_single_cal_span_target
ozonePrecursor_i-Pentane_single_cal_span_drift
ozonePrecursor_n-Pentane_single_cal_span_actual
ozonePrecursor_n-Pentane_single_cal_span_target
ozonePrecursor_n-Pentane_single_cal_span_drift
ozonePrecursor_1_3-Butadiene_single_cal_span_actual
ozonePrecursor_1_3-Butadiene_single_cal_span_target
ozonePrecursor_1_3-Butadiene_single_cal_span_drift
ozonePrecursor_trans-2-Pentene_single_cal_span_actual
ozonePrecursor_trans-2-Pentene_single_cal_span_target
ozonePrecursor_trans-2-Pentene_single_cal_span_drift
ozonePrecursor_1-Pentene_single_cal_span_actual
ozonePrecursor_1-Pentene_single_cal_span_target
ozonePrecursor_1-Pentene_single_cal_span_drift
ozonePrecursor_cis-2-Pentene_single_cal_span_actual
ozonePrecursor_cis-2-Pentene_single_cal_span_target
ozonePrecursor_cis-2-Pentene_single_cal_span_drift
ozonePrecursor_2-Methylpentane_single_cal_span_actual
ozonePrecursor_2-Methylpentane_single_cal_span_target
ozonePrecursor_2-Methylpentane_single_cal_span_drift
ozonePrecursor_n-Hexane(VOC)_single_cal_span_actual
ozonePrecursor_n-Hexane(VOC)_single_cal_span_target
ozonePrecursor_n-Hexane(VOC)_single_cal_span_drift
ozonePrecursor_Isoprene_single_cal_span_actual
ozonePrecursor_Isoprene_single_cal_span_target
ozonePrecursor_Isoprene_single_cal_span_drift
so2_maintenance
nox_maintenance
co_maintenance
o3_maintenance
teom_maintenance
ozonePrecursor_maintenance
aio_maintenance
so2_repair
nox_repair
co_repair
o3_repair
teom_repair
aio_repair
ozonePrecursor_repair
nox_flag
so2_flag
o3_flag
co_flag
aio_flag
ozone_precursor_flag
teom_flag
teom_teom_a_dryer_dew
teom_teom_b_dryer_dew
teom_a_cooler_temperature
teom_a_base_mass_conc
teom_a_ref_mass_conc
teom_b_cooler_temp
teom_b_base_mass_conc
teom_b_ref_mass_conc
diagnostic_teom_a
diagnostic_teom_b

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,88 @@
using System.Reflection;
namespace Udara.Infrastructure.Chronolog;
public class Chronolog : ILogger
{
private readonly string _categoryName;
private readonly string _logFilePath;
private readonly object _lock;
public Chronolog(string categoryName, string logFilePath, object logLock)
{
Assembly? entryAssembly = Assembly.GetEntryAssembly();
var rootNamespace = entryAssembly?.GetName().Name ?? string.Empty;
_categoryName = categoryName.StartsWith(rootNamespace + ".")
? categoryName.Substring(categoryName.LastIndexOf('.') + 1)
: categoryName;
_logFilePath = logFilePath;
_lock = logLock;
}
IDisposable ILogger.BeginScope<TState>(TState state) => null!;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId,
TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
var logTimeStamp = DateTime.Now.ToString("yyyyMMdd-HHmmssff");
var logLevelString = logLevel.ToString();
var logMessage = formatter(state, exception);
const string crlf = "\r\n";
logMessage = logMessage.Replace(crlf, crlf + "\t");
var logLine = $"[{logTimeStamp}][{_categoryName}][{logLevelString}]\r\n\t{logMessage}";
lock (_lock)
{
Directory.CreateDirectory(Path.GetDirectoryName(_logFilePath)!);
File.AppendAllText(_logFilePath, logLine + Environment.NewLine);
}
if (!Console.IsOutputRedirected)
{
WriteColored(logLevel, logLine);
}
}
private static void WriteColored(LogLevel level, string message)
{
var originalFg = Console.ForegroundColor;
var originalBg = Console.BackgroundColor;
switch (level)
{
case LogLevel.Trace:
case LogLevel.Debug:
Console.ForegroundColor = ConsoleColor.Gray;
break;
case LogLevel.Information:
Console.ForegroundColor = ConsoleColor.DarkGreen;
break;
case LogLevel.Warning:
Console.ForegroundColor = ConsoleColor.Yellow;
break;
case LogLevel.Error:
Console.ForegroundColor = ConsoleColor.Red;
break;
case LogLevel.Critical:
Console.ForegroundColor = ConsoleColor.White;
Console.BackgroundColor = ConsoleColor.Red;
break;
default:
break;
}
Console.WriteLine(message);
Console.ForegroundColor = originalFg;
Console.BackgroundColor = originalBg;
}
}

View File

@ -0,0 +1,57 @@
using System.IO.Compression;
namespace Udara.Infrastructure.Chronolog;
public class ChronologProvider : ILoggerProvider
{
private readonly object _lock = new();
private readonly string _logDirectory;
public ChronologProvider()
{
_logDirectory = Path.Combine(AppContext.BaseDirectory, "Logs");
Directory.CreateDirectory(_logDirectory);
ArchiveOldLogs();
}
public ILogger CreateLogger(string categoryName)
{
var logFileName = $"{DateTime.Now:yyyyMMdd}.log";
var logPath = Path.Combine(_logDirectory, logFileName);
return new Chronolog(categoryName, logPath, _lock);
}
private void ArchiveOldLogs()
{
var cutoffDate = DateTime.Now.AddMonths(-3);
var logFiles = Directory.GetFiles(_logDirectory, "*.log");
var groups = logFiles
.Select(path => new FileInfo(path))
.Where(fi => fi.LastWriteTime < cutoffDate)
.GroupBy(fi => fi.Name.Substring(0, 6)
);
foreach (var group in groups)
{
var year = group.Key.Substring(0, 4);
var archiveDir = Path.Combine(_logDirectory, "Archive", year);
Directory.CreateDirectory(archiveDir);
var archivePath = Path.Combine(archiveDir, $"{group.Key}.zip");
using var archive = new ZipArchive(
new FileStream(archivePath, FileMode.OpenOrCreate),
ZipArchiveMode.Update
);
foreach (var file in group)
{
archive.CreateEntryFromFile(file.FullName, file.Name);
File.Delete(file.FullName);
}
}
}
public void Dispose() { }
}

View File

@ -0,0 +1,21 @@
using System.Text;
namespace Udara.Infrastructure.FileSystem;
public sealed class FileReader : IFileReader
{
public async Task<string> ReadAllTextAsync(string path, CancellationToken token)
{
if (!File.Exists(path))
return string.Empty;
using var stream = File.OpenRead(path);
using var reader = new StreamReader(stream, Encoding.UTF8);
return await reader.ReadToEndAsync(token);
}
public Task<bool> ExistsAsync(string path, CancellationToken token)
{
return Task.FromResult(File.Exists(path));
}
}

View File

@ -0,0 +1,7 @@
namespace Udara.Infrastructure.FileSystem;
public interface IFileReader
{
Task<string> ReadAllTextAsync(string path, CancellationToken token);
Task<bool> ExistsAsync(string path, CancellationToken token);
}

View File

@ -0,0 +1,76 @@
using System.Text.RegularExpressions;
namespace Udara.Infrastructure.FileTransfer;
public sealed class FileTransfer : IFileTransfer
{
private readonly string _root;
public FileTransfer()
{
_root = Path.Combine(AppContext.BaseDirectory, "Workplace", "FileProcessing");
Directory.CreateDirectory(_root);
}
public async Task<IReadOnlyList<string>> CollectFilesAsync(
string fileProcessName,
string targetPath,
string filePattern,
string extension,
CancellationToken token)
{
var baseDir = Path.Combine(_root, fileProcessName);
var collectionDir = Path.Combine(baseDir, "Collection");
var processedDir = Path.Combine(baseDir, "Processed");
Directory.CreateDirectory(collectionDir);
Directory.CreateDirectory(processedDir);
var regexPattern = $"^{Regex.Escape(filePattern)}.*$";
var regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
var files = Directory
.EnumerateFiles(targetPath, $"*.{extension}", SearchOption.TopDirectoryOnly)
.Where(path => regex.IsMatch(Path.GetFileName(path)))
.ToList();
var results = new List<string>();
foreach (var file in files)
{
token.ThrowIfCancellationRequested();
var filename = Path.GetFileName(file);
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmssff");
var newName = $"{timestamp}_{filename}";
var destPath = Path.Combine(collectionDir, newName);
File.Copy(file, destPath, overwrite: false);
if (File.Exists(destPath))
{
File.Delete(file);
results.Add(destPath);
}
await Task.Delay(500);
}
return results;
}
public async Task ProcessedFilesAsync(string sourceFile, CancellationToken token)
{
var collectionDir = Path.GetDirectoryName(sourceFile)!;
var rootDir = Directory.GetParent(collectionDir)!.FullName;
var processedDir = Path.Combine(rootDir, "Processed");
if (!Directory.Exists(processedDir))
Directory.CreateDirectory(processedDir);
var destFile = Path.Combine(processedDir, Path.GetFileName(sourceFile));
File.Move(sourceFile, destFile, overwrite: true);
await Task.Delay(500);
}
}

View File

@ -0,0 +1,12 @@
namespace Udara.Infrastructure.FileTransfer;
public interface IFileTransfer
{
Task<IReadOnlyList<string>> CollectFilesAsync(
string processName,
string targetDir,
string filePattern,
string extension,
CancellationToken token);
Task ProcessedFilesAsync(string sourceFile, CancellationToken token);
}

View File

@ -0,0 +1,18 @@
namespace Udara.Infrastructure.Ftp;
public sealed class FtpConfig
{
public string Host { get; init; } = string.Empty;
public int Port { get; init; } = 21;
public string Username { get; init; } = string.Empty;
public string Password { get; init; } = string.Empty;
// ftp, ftps, sftp
public string Protocol { get; init; } = "ftp";
// true = passive, false = active
public bool Passive { get; init; } = true;
public string RemoteDirectory { get; init; } = "/";
}

View File

@ -0,0 +1,61 @@
using WinSCP;
namespace Udara.Infrastructure.Ftp;
public sealed class FtpUploader : IFtpUploader
{
private readonly ILogger<FtpUploader> _logger;
public FtpUploader(ILogger<FtpUploader> logger)
{
_logger = logger;
}
public async Task UploadAsync(
string localFilePath,
string remoteFileName,
FtpConfig config,
CancellationToken token)
{
var sessionOptions = new WinSCP.SessionOptions
{
HostName = config.Host,
PortNumber = config.Port,
UserName = config.Username,
Password = config.Password,
Protocol = config.Protocol.ToLower() switch
{
"ftp" => Protocol.Ftp,
"sftp" => Protocol.Sftp,
"ftps" => Protocol.Ftp,
_ => Protocol.Ftp
},
FtpMode = config.Passive ? FtpMode.Passive : FtpMode.Active,
TlsHostCertificateFingerprint = null
};
using var session = new Session();
session.Open(sessionOptions);
var baseDir = string.IsNullOrWhiteSpace(config.RemoteDirectory) ? "/" : config.RemoteDirectory.TrimEnd('/');
var remotePath = $"{baseDir}/{remoteFileName}";
var transferOptions = new TransferOptions
{
TransferMode = TransferMode.Binary
};
var result = session.PutFiles(localFilePath, remotePath, false, transferOptions);
result.Check();
_logger.LogInformation(
"Uploaded {Local} to {Remote} on {Host}",
localFilePath, remotePath, config.Host
);
await Task.CompletedTask;
}
}

View File

@ -0,0 +1,11 @@
namespace Udara.Infrastructure.Ftp;
public interface IFtpUploader
{
Task UploadAsync(
string localFilePath,
string remoteFileName,
FtpConfig config,
CancellationToken token
);
}

View File

@ -0,0 +1,45 @@
namespace Udara.Infrastructure.Logging;
public class AppFileLogger : ILogger
{
private readonly string _path;
private static readonly object _lock = new();
public AppFileLogger(string path)
{
_path = path;
}
IDisposable ILogger.BeginScope<TState>(TState state)
{
return NullScope.Instance;
}
bool ILogger.IsEnabled(LogLevel logLevel)
{
return true;
}
void ILogger.Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception? exception,
Func<TState, Exception?, string> formatter)
{
var message = formatter(state, exception);
lock (_lock)
{
File.AppendAllText(
_path,
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{logLevel}] {message}{Environment.NewLine}");
}
}
private class NullScope : IDisposable
{
public static readonly NullScope Instance = new();
public void Dispose() { }
}
}

View File

@ -0,0 +1,16 @@
namespace Udara.Infrastructure.Logging;
public class AppFileLoggerProvider : ILoggerProvider
{
private readonly string _path;
public AppFileLoggerProvider(string path)
{
_path = path;
}
public ILogger CreateLogger(string categoryName)
=> new AppFileLogger(_path);
public void Dispose() { }
}

View File

@ -0,0 +1,10 @@
namespace Udara.Infrastructure.ProcessExecutor;
public interface IProcessExecutor
{
Task<ProcessExecutorResult> ExecuteAsync(
string executablePath,
IEnumerable<string> arguments,
CancellationToken token
);
}

View File

@ -0,0 +1,54 @@
using System.Diagnostics;
using System.Text;
namespace Udara.Infrastructure.ProcessExecutor;
public class ProcessExecutor : IProcessExecutor
{
private readonly ILogger<ProcessExecutor> _logger;
public ProcessExecutor(ILogger<ProcessExecutor> logger)
{
_logger = logger;
}
public async Task<ProcessExecutorResult> ExecuteAsync(
string executablePath,
IEnumerable<string> arguments,
CancellationToken token)
{
var psi = new ProcessStartInfo
{
FileName = executablePath,
RedirectStandardOutput = true,
RedirectStandardError = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8,
UseShellExecute = false,
CreateNoWindow = true
};
foreach (var arg in arguments)
psi.ArgumentList.Add(arg);
using var process = new Process { StartInfo = psi };
process.Start();
var stdoutTask = process.StandardOutput.ReadToEndAsync(token);
var stderrTask = process.StandardError.ReadToEndAsync(token);
await Task.WhenAll(stdoutTask, stderrTask);
var result = new ProcessExecutorResult
{
ExitCode = process.ExitCode,
StandardOutput = stdoutTask.Result ?? string.Empty,
StandardError = stderrTask.Result ?? string.Empty
};
await process.WaitForExitAsync(token);
return result;
}
}

View File

@ -0,0 +1,8 @@
namespace Udara.Infrastructure.ProcessExecutor;
public sealed class ProcessExecutorResult
{
public int ExitCode { get; set; }
public string StandardOutput { get; set; } = string.Empty;
public string StandardError { get; set; } = string.Empty;
}

View File

@ -0,0 +1,12 @@
namespace Udara.Infrastructure.Serial;
public interface ISerialPortClient : IDisposable
{
Task<string> SendAndReceiveAsync(string command, CancellationToken token);
Task<string> WaitForDataAsync(CancellationToken token);
Task SendCommandAsync(string command, CancellationToken token);
Task SendBytesAsync(byte[] data, CancellationToken token);
int ReadByte();
int BytesToRead { get; }
}

View File

@ -0,0 +1,10 @@
using Udara.Database.App.Model;
namespace Udara.Infrastructure.Serial;
public interface ISerialPortFactory
{
ISerialPortClient Create(string portName, int baudRate);
ISerialPortClient Create(DeviceSerialModel serialModel);
ISerialPortClient Create(DeviceSerialModel serialModel, bool binaryMode);
}

View File

@ -0,0 +1,158 @@
using System.Collections.Concurrent;
using System.IO.Ports;
using System.Text;
using Udara.Database.App.Model;
namespace Udara.Infrastructure.Serial;
public sealed class SerialPortClient : ISerialPortClient
{
private readonly SerialPort _port;
private readonly ConcurrentQueue<string> _queue = new();
private readonly bool _binaryMode;
public SerialPortClient(string portName, int baudRate)
{
_port = new SerialPort(portName, baudRate);
_port.DataReceived += OnDataReceived;
_port.Open();
}
public SerialPortClient(DeviceSerialModel serialModel)
: this(serialModel,false)
{
}
public SerialPortClient(DeviceSerialModel serialModel, bool binaryMode)
{
_binaryMode = binaryMode;
_port = new SerialPort()
{
PortName = serialModel.PortName,
BaudRate = serialModel.BaudRate,
DataBits = serialModel.DataBits,
Parity = ParseParity(serialModel.Parity),
StopBits = ParseStopBits(serialModel.StopBits),
Handshake = ParseHandshake(serialModel.FlowControl),
Encoding = ParseEncoding(serialModel.Encoding),
NewLine = ParseNewLine(serialModel.NewLine),
ReadTimeout = serialModel.ReadTimeout,
WriteTimeout = serialModel.WriteTimeout
};
if (!_binaryMode)
_port.DataReceived += OnDataReceived;
_port.Open();
}
private void OnDataReceived(object? sender, SerialDataReceivedEventArgs e)
{
try
{
var line = _port.ReadLine();
_queue.Enqueue(line);
}
catch
{
// ignore or log
}
}
public async Task<string> SendAndReceiveAsync(string command, CancellationToken token)
{
_port.WriteLine(command);
while (!token.IsCancellationRequested)
{
if (_queue.TryDequeue(out var line))
return line;
await Task.Delay(10, token);
}
return string.Empty;
}
public async Task<string> WaitForDataAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
if (_queue.TryDequeue(out var line))
return line;
await Task.Delay(10, token);
}
return string.Empty;
}
public Task SendCommandAsync(string command, CancellationToken token)
{
_port.WriteLine(command);
return Task.CompletedTask;
}
public int ReadByte() => _port.ReadByte();
public int BytesToRead => _port.BytesToRead;
public Task SendBytesAsync(byte[] data, CancellationToken token)
{
_port.Write(data, 0, data.Length);
return Task.CompletedTask;
}
public void Dispose()
{
try
{
_port.DataReceived -= OnDataReceived;
if (_port.IsOpen)
_port.Close();
_port.Dispose();
}
catch { }
}
private static Parity ParseParity(string p) =>
p.ToLower() switch
{
"none" => Parity.None,
"odd" => Parity.Odd,
"even" => Parity.Even,
_ => Parity.None
};
private static StopBits ParseStopBits(int s) =>
s switch
{
1 => StopBits.One,
2 => StopBits.Two,
_ => StopBits.One
};
private static Handshake ParseHandshake(string f) =>
f.ToLower() switch
{
"none" => Handshake.None,
"xonxoff" => Handshake.XOnXOff,
"rts" => Handshake.RequestToSend,
"rtsxonxoff" => Handshake.RequestToSendXOnXOff,
_ => Handshake.None
};
private static string ParseNewLine(string n) =>
n.ToLower() switch
{
"crlf" => "\r\n",
"lf" => "\n",
"cr" => "\r",
_ => "\n"
};
private static Encoding ParseEncoding(string e) =>
e.ToLower() switch
{
"ascii" => Encoding.ASCII,
"utf-8" => Encoding.UTF8,
_ => Encoding.ASCII
};
}

View File

@ -0,0 +1,13 @@
using Udara.Database.App.Model;
namespace Udara.Infrastructure.Serial;
public sealed class SerialPortFactory : ISerialPortFactory
{
public ISerialPortClient Create(string portName, int baudRate)
=> new SerialPortClient(portName, baudRate);
public ISerialPortClient Create(DeviceSerialModel serialModel)
=> new SerialPortClient(serialModel);
public ISerialPortClient Create(DeviceSerialModel model, bool binaryMode = false)
=> new SerialPortClient(model, binaryMode);
}

View File

@ -0,0 +1,6 @@
namespace Udara.Infrastructure.Telegram;
public interface ITelegramApi
{
Task SendMessageAsync(string text, CancellationToken token = default);
}

View File

@ -0,0 +1,23 @@
using Udara.Common.Feature.Telegram;
namespace Udara.Infrastructure.Telegram;
public class TelegramApi : ITelegramApi
{
private readonly HttpClient _httpClient;
private readonly ITelegramSettingsProvider _settingsProvider;
public TelegramApi(HttpClient httpClient, ITelegramSettingsProvider settingsProvider)
{
_httpClient = httpClient;
_settingsProvider = settingsProvider;
}
public async Task SendMessageAsync(string text, CancellationToken token = default)
{
var settings = await _settingsProvider.GetSettingsAsync(token);
var url = $"{settings.Protocol}://{settings.Host}/{settings.Mode}{settings.Token}/{settings.Method}";
var payload = new { chat_id = settings.TargetChatId, text };
await _httpClient.PostAsJsonAsync(url, payload);
}
}

222
Udara/Program.cs Normal file
View File

@ -0,0 +1,222 @@
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.EntityFrameworkCore;
using System.Security.Cryptography.X509Certificates;
using Udara.Common.Feature.Csv;
using Udara.Common.Feature.Telegram;
using Udara.Common.Feature.Time;
using Udara.Database.App;
using Udara.Database.Data;
using Udara.Infrastructure.Chronolog;
using Udara.Infrastructure.FileSystem;
using Udara.Infrastructure.FileTransfer;
using Udara.Infrastructure.Ftp;
using Udara.Infrastructure.Logging;
using Udara.Infrastructure.ProcessExecutor;
using Udara.Infrastructure.Serial;
using Udara.Infrastructure.Telegram;
using Udara.SvcApp;
using Udara.SvcApp.Poll.Processor;
using Udara.SvcApp.Poll.Processor.Interface;
using Udara.SvcApp.Poll.Processor.Mode;
namespace Udara;
public class Program
{
public static readonly string AppDbFileName = $"app.db";
public static readonly string DataDbFileName = $"data.db";
public static readonly string CertFileName = $"cert.pem";
public static readonly string MvcDirName = "WebApp";
public static readonly string _databaseDir = Path.Combine(AppContext.BaseDirectory, "Database");
public static readonly string _logDir = Path.Combine(AppContext.BaseDirectory, "Logs");
public static readonly string _toolDir = Path.Combine(AppContext.BaseDirectory, "Tools");
public static readonly string _appDbFilePath = Path.Combine(_databaseDir, AppDbFileName);
public static readonly string _dataDbFilePath = Path.Combine(_databaseDir, DataDbFileName);
public class ProgramConfigs
{
public string ProjectName { get; set; } = null!;
public string KestrelHost { get; set; } = null!;
public string KestrelPort { get; set; } = null!;
}
//public class LogConfigs
//{
// public string AppLogPath { get; set; } = null!;
// public string SvcLogPath { get; set; } = null!;
// public string WebLogPath { get; set; } = null!;
//}
//private static readonly string _appLogPath = Path.Combine(_logFolder, $"{ProjectName}-App.log");
//private static readonly string _svcLogPath = Path.Combine(_logFolder, $"{ProjectName}-Svc.log");
//private static readonly string _webLogPath = Path.Combine(_logFolder, $"{ProjectName}-Web.log");
private static ProgramConfigs GetProgramConfigs()
{
try
{
ProgramConfigs configs = new();
var appDbPath = Path.Combine(_databaseDir, AppDbFileName);
var dbcOptions = new DbContextOptionsBuilder<AppDbContext>().UseSqlite($"Data Source={_appDbFilePath}").Options;
var db = new AppDbContext(dbcOptions);
var configsList = db.AppConfigs.ToList();
configsList.ForEach(row =>
{
var key = row.ConfigKey;
var val = row.ConfigValue;
switch (key)
{
case "ProjectName":
configs.ProjectName = val; break;
case "KestrelHost":
configs.KestrelHost = val; break;
case "KestrelPort":
configs.KestrelPort = val; break;
default: break;
}
});
return configs;
}
catch (Exception)
{
return null!;
}
}
public static void Main(string[] args)
{
// Initial Checks
if (!Directory.Exists(_logDir)) Directory.CreateDirectory(_logDir);
if (!File.Exists(_appDbFilePath)) throw new FileNotFoundException();
// Initial Configs
ProgramConfigs configs = GetProgramConfigs();
if (configs == null) throw new NullReferenceException();
Console.WriteLine("Hello World");
Console.WriteLine("ProjectName: " + configs.ProjectName);
// Init WebApp Builder
var builder = WebApplication.CreateBuilder(args);
//// Init Reloadable AppSettings
//builder.Configuration
// .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
// .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);
// Init Chronolog Logger
builder.Logging.ClearProviders();
//builder.Logging.AddProvider(new ChronologProvider());
builder.Services.AddSingleton<ILoggerProvider, ChronologProvider>();
// Init Service Register
if (OperatingSystem.IsWindows())
{
// Enable Windows Service hosting
builder.Services.AddWindowsService(options =>
{
options.ServiceName = configs.ProjectName;
});
}
// Init EF Core
builder.Services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlite($"Data Source={_appDbFilePath}");
});
builder.Services.AddDbContext<DataDbContext>(options =>
{
options.UseSqlite($"Data Source={_dataDbFilePath}");
});
//using (var scope = builder.Services.BuildServiceProvider().CreateScope())
//{
// var raw = scope.ServiceProvider.GetRequiredService<DataDbContext>();
// raw.Database.EnsureCreated();
//}
// Init Cert
var cert = new X509Certificate2(Path.Combine(_toolDir, CertFileName));
// Init HttpClient
using var httpClient = new HttpClientHandler();
httpClient.ClientCertificates.Add(cert);
// Init Main Worker
builder.Services.AddHostedService<SvcWorker>();
// Init Feature
builder.Services.AddSingleton<IMinuteAlignment, MinuteAlignment>();
builder.Services.AddSingleton<ICsvParser, CsvParser>();
builder.Services.AddSingleton<ITelegramSettingsProvider, TelegramSettingsProvider>();
// Init Infrastructure
builder.Services.AddSingleton<IProcessExecutor, ProcessExecutor>();
builder.Services.AddSingleton<IFileReader, FileReader>();
builder.Services.AddSingleton<IFileTransfer, FileTransfer>();
builder.Services.AddSingleton<ISerialPortFactory, SerialPortFactory>();
builder.Services.AddSingleton<IFtpUploader, FtpUploader>();
builder.Services.AddHttpClient<ITelegramApi,TelegramApi>().ConfigurePrimaryHttpMessageHandler(() => httpClient);
builder.Services.AddScoped<IDeviceProcessorFactory, DeviceProcessorFactory>();
builder.Services.AddScoped<IProcessorResultCollector, ProcessorResultCollector>();
builder.Services.AddTransient<AioProcessor>();
builder.Services.AddTransient<IDeviceProcessor, AioProcessor>();
builder.Services.AddTransient<AkProcessor>();
builder.Services.AddTransient<IDeviceProcessor, AkProcessor>();
builder.Services.AddTransient<AmaProcessor>();
builder.Services.AddTransient<IDeviceProcessor, AmaProcessor>();
builder.Services.AddTransient<ModbusProcessor>();
builder.Services.AddTransient<IDeviceProcessor, ModbusProcessor>();
builder.Services.AddTransient<CsvProcessor>();
builder.Services.AddTransient<IDeviceProcessor, CsvProcessor>();
// Init .NET MVC
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddControllersWithViews();
// Modify Razor 'Area' and 'View' location
builder.Services.Configure<RazorViewEngineOptions>(options =>
{
var uniqueViewFormat = "/" + MvcDirName + "/Views/{1}/{0}";
var sharedViewFormat = "/" + MvcDirName + "/Views/Shared/{0}";
options.ViewLocationFormats.Clear();
options.ViewLocationFormats.Add(uniqueViewFormat + RazorViewEngine.ViewExtension);
options.ViewLocationFormats.Add(sharedViewFormat + RazorViewEngine.ViewExtension);
options.AreaViewLocationFormats.Clear();
options.AreaViewLocationFormats.Add(uniqueViewFormat + RazorViewEngine.ViewExtension);
options.AreaViewLocationFormats.Add(sharedViewFormat + RazorViewEngine.ViewExtension);
});
builder.WebHost.UseStaticWebAssets();
// Remove Logging
//builder.Logging.ClearProviders();
// Init WebApp
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run($"http://{configs.KestrelHost}:{configs.KestrelPort}");
app.StopAsync();
}
}

View File

@ -0,0 +1,30 @@
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:7789",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": ""
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:55630",
"sslPort": 0
}
}
}

View File

@ -0,0 +1,6 @@
namespace Udara.SvcApp.Poll.Processor;
public class DataLoggingBatch
{
public List<DeviceResultSnapshot> Devices { get; set; } = [];
}

View File

@ -0,0 +1,31 @@
using Udara.Database.App.Model;
using Udara.SvcApp.Poll.Processor.Interface;
using Udara.SvcApp.Poll.Processor.Mode;
namespace Udara.SvcApp.Poll.Processor;
public class DeviceProcessorFactory : IDeviceProcessorFactory
{
private readonly IServiceProvider _services;
public DeviceProcessorFactory(IServiceProvider services)
{
_services = services;
}
public IDeviceProcessor? Create(DeviceListModel device)
{
var mode = device.Mode?.ToLowerInvariant();
return mode switch
{
"modbus" => _services.GetRequiredService<ModbusProcessor>(),
"serial" => _services.GetRequiredService<AioProcessor>(),
"sqlserver" => _services.GetRequiredService<AmaProcessor>(),
"ak" => _services.GetRequiredService<AkProcessor>(),
"csv" => _services.GetService<CsvProcessor>(),
_ => null
};
}
}

View File

@ -0,0 +1,13 @@
namespace Udara.SvcApp.Poll.Processor;
public class DeviceResultSnapshot
{
public int DeviceId { get; set; }
public string Code { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Mode { get; set; } = string.Empty;
public Dictionary<string, string> Parameters { get; set; }
= new(StringComparer.OrdinalIgnoreCase);
public Dictionary<string, string> Flags { get; set; }
= new(StringComparer.OrdinalIgnoreCase);
}

View File

@ -0,0 +1,8 @@
using Udara.Database.App.Model;
namespace Udara.SvcApp.Poll.Processor.Interface;
public interface IDeviceProcessor
{
Task ProcessAsync(DeviceListModel device, CancellationToken token);
}

View File

@ -0,0 +1,7 @@
using Udara.Database.App.Model;
using Udara.SvcApp.Poll.Processor.Interface;
public interface IDeviceProcessorFactory
{
IDeviceProcessor? Create(DeviceListModel device);
}

View File

@ -0,0 +1,5 @@
namespace Udara.SvcApp.Poll.Processor.Interface;
public interface IDeviceResult
{
}

View File

@ -0,0 +1,9 @@
using Udara.Database.App.Model;
namespace Udara.SvcApp.Poll.Processor.Interface;
public interface IProcessorResultCollector
{
void BeginBatch(IReadOnlyCollection<DeviceListModel> devices, DateTime Timestamp);
Task CollectAsync(DeviceListModel device, IDeviceResult result, CancellationToken token);
}

View File

@ -0,0 +1,132 @@
using Microsoft.EntityFrameworkCore;
using Udara.Database.App;
using Udara.Database.App.Model;
using Udara.Infrastructure.Serial;
using Udara.SvcApp.Poll.Processor.Interface;
namespace Udara.SvcApp.Poll.Processor.Mode;
public class AioResult : IDeviceResult
{
public DeviceListModel Device { get; set; } = default!;
public Dictionary<string, string> Parameters { get; set; } = new();
}
public class AioProcessor : IDeviceProcessor
{
private readonly ILogger<AioProcessor> _logger;
private readonly IProcessorResultCollector _collector;
private readonly AppDbContext _db;
private readonly ISerialPortFactory _serialPortFactory;
public AioProcessor(
ILogger<AioProcessor> logger,
IProcessorResultCollector collector,
AppDbContext db,
ISerialPortFactory serialPortFactory
)
{
_logger = logger;
_collector = collector;
_db = db;
_serialPortFactory = serialPortFactory;
}
public async Task ProcessAsync(DeviceListModel device, CancellationToken token)
{
var serial = await _db.DeviceSerial
.AsNoTracking()
.FirstOrDefaultAsync(x => x.DeviceId == device.Id, token);
if (serial == null)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceSerial entry found", device.Id);
return;
}
var parameters = await _db.DeviceParameters
.AsNoTracking()
.Where(x => x.DeviceId == device.Id)
.OrderBy(x => x.ParameterId)
.ToListAsync(token);
if (parameters.Count == 0)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceParameters entry found", device.Id);
return;
}
// Always initialize dictionary with all register names = ""
var aioData = parameters.ToDictionary(r => r.ParameterName, _ => "");
string? serialLine = null;
try
{
using var client = _serialPortFactory.Create(serial);
serialLine = await client.WaitForDataAsync(token);
if (!string.IsNullOrWhiteSpace(serialLine))
{
// Parsing Data
var parsed = await ParseAioLineAsync(device.Id, serialLine, parameters, token);
// Overwrite only the values that were parsed
foreach (var kv in parsed)
aioData[kv.Key] = kv.Value;
}
else
{
_logger.LogWarning("DeviceId {DeviceId}: Empty AIO line received", device.Id);
}
}
catch (TimeoutException)
{
_logger.LogError("DeviceId {DeviceId}: Timeout reading from AIO device", device.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "DeviceId {DeviceId}: Error reading AIO device", device.Id);
}
finally
{
var result = new AioResult
{
Device = device,
Parameters = aioData
};
await _collector.CollectAsync(device, result, token);
}
}
private Task<Dictionary<string, string>> ParseAioLineAsync(
int deviceId,
string line,
List<DeviceParametersModel> parameters,
CancellationToken token
)
{
var parts = line.Trim().Split(',');
var dict = new Dictionary<string, string>();
for (int i = 0; i < parameters.Count; i++)
{
if (i >= parts.Length)
{
dict[parameters[i].ParameterName] = "";
continue;
}
string value = parts[i];
if (parameters[i].ParameterName == "Checksum")
value = value.TrimStart('*');
dict[parameters[i].ParameterName] = value;
}
return Task.FromResult(dict);
}
}

View File

@ -0,0 +1,244 @@
using Microsoft.EntityFrameworkCore;
using System.Text;
using Udara.Database.App;
using Udara.Database.App.Model;
using Udara.Infrastructure.Serial;
using Udara.SvcApp.Poll.Processor.Interface;
namespace Udara.SvcApp.Poll.Processor.Mode;
public class AkResult : IDeviceResult
{
public DeviceListModel Device { get; set; } = default!;
public Dictionary<string, string> Parameters { get; set; }
= new();
}
public class AkProcessor : IDeviceProcessor
{
private readonly AppDbContext _db;
private readonly ILogger<AkProcessor> _logger;
private readonly IProcessorResultCollector _collector;
private readonly ISerialPortFactory _serialPortFactory;
public AkProcessor(
AppDbContext db,
ILogger<AkProcessor> logger,
IProcessorResultCollector collector,
ISerialPortFactory serialPortFactory
)
{
_db = db;
_logger = logger;
_collector = collector;
_serialPortFactory = serialPortFactory;
}
public async Task ProcessAsync(DeviceListModel device, CancellationToken token)
{
var serial = await _db.DeviceSerial
.AsNoTracking()
.FirstOrDefaultAsync(x => x.DeviceId == device.Id, token);
if (serial == null)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceSerial entry found", device.Id);
return;
}
var parameters = await _db.DeviceParameters
.AsNoTracking()
.Where(x => x.DeviceId == device.Id)
.OrderBy(x => x.ParameterId)
.ToListAsync(token);
if (parameters.Count == 0)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceRegisters entry found", device.Id);
return;
}
// Always initialize dictionary with all register names = ""
var akData = parameters.ToDictionary(r => r.ParameterName, _ => "");
try
{
using var client = _serialPortFactory.Create(serial, binaryMode: true);
foreach (var reg in parameters)
{
token.ThrowIfCancellationRequested();
var prc = reg.ParameterId;
var request = BuildRequest(prc.ToString());
await client.SendBytesAsync(request, token);
// Allow TEOM/AK device time to process each command
await Task.Delay(50, token);
var response = ReadResponse(device, client, prc);
if (response.IsError)
{
_logger.LogWarning(
"DeviceId {DeviceId}: PRC {PRC} returned error {ErrorType}",
device.Id, prc, response.ErrorType
);
akData[reg.ParameterName] = "";
continue;
}
akData[reg.ParameterName] = response.Value;
}
}
catch (TimeoutException)
{
_logger.LogError("DeviceId {DeviceId}: Timeout reading from AK device", device.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "DeviceId {DeviceId}: Error reading AK device", device.Id);
}
finally
{
var result = new AkResult
{
Device = device,
Parameters = akData
};
await _collector.CollectAsync(device, result, token);
}
}
private static byte[] BuildRequest(string prc)
{
var body = $"4AREG K0 {prc}";
var bytes = new List<byte>();
bytes.Add(0x02); // STX
bytes.AddRange(Encoding.ASCII.GetBytes(body));
bytes.Add(0x03); // ETX
return bytes.ToArray();
}
private AkResponse ReadResponse(
DeviceListModel device,
ISerialPortClient client,
int prc
)
{
var buffer = new List<byte>();
bool inFrame = false;
while (true)
{
int b = client.ReadByte();
if (!inFrame)
{
// Ignore everything until STX
if (b == 0x02)
{
inFrame = true;
buffer.Add((byte)b);
}
continue;
}
// Inside STX..ETX
buffer.Add((byte)b);
if (b == 0x03)
{
// ETX reached → frame complete
break;
}
}
// After ETX, discard CR/LF if present
while (client.BytesToRead > 0)
{
int next = client.ReadByte();
if (next != 0x0D && next != 0x0A)
{
// Not CR/LF → TEOM never sends meaningful data after ETX.
break;
}
}
_logger.LogInformation(
"DeviceId {DeviceId}: PRC {PRC} raw frame: {Frame}",
device.Id,
prc,
ToCEscaped(buffer.ToArray())
);
return ParseResponse(buffer.ToArray());
}
private AkResponse ParseResponse(byte[] frame)
{
if (frame.Length < 5)
return AkResponse.Error("InvalidFrame");
if (frame[0] != 0x02 || frame[^1] != 0x03)
return AkResponse.Error("BadSTXETX");
var text = Encoding.ASCII.GetString(frame, 1, frame.Length - 2);
var parts = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 3)
return AkResponse.Error("Malformed");
var header = parts[0];
var warning = parts[1];
var prc = parts[2];
if (header.StartsWith("4???"))
return AkResponse.Error("UnrecognizedCommand");
if (prc == "SE")
return AkResponse.Error("SyntaxError");
if (parts.Length < 4)
return AkResponse.Error("MissingValue");
var value = parts[3];
return AkResponse.Success(value);
}
private class AkResponse
{
public bool IsError { get; private set; }
public string ErrorType { get; private set; } = "";
public string Value { get; private set; } = "";
public static AkResponse Success(string value) =>
new AkResponse { IsError = false, Value = value };
public static AkResponse Error(string type) =>
new AkResponse { IsError = true, ErrorType = type };
}
private static string ToCEscaped(byte[] data)
{
var sb = new StringBuilder(data.Length * 4);
foreach (var b in data)
{
if (b >= 0x20 && b <= 0x7E)
{
sb.Append((char)b);
}
else
{
sb.Append($"\\x{b:X2}");
}
}
return sb.ToString();
}
}

View File

@ -0,0 +1,192 @@
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Data;
using System.Text.Json;
using Udara.Database.App;
using Udara.Database.App.Model;
using Udara.SvcApp.Poll.Processor.Interface;
namespace Udara.SvcApp.Poll.Processor.Mode;
public class AmaResult : IDeviceResult
{
public DeviceListModel Device { get; set; } = default!;
public Dictionary<string, string> Parameters { get; set; } = new();
}
public class AmaProcessor : IDeviceProcessor
{
private readonly ILogger<AmaProcessor> _logger;
private readonly AppDbContext _db;
private readonly IProcessorResultCollector _collector;
public AmaProcessor(
ILogger<AmaProcessor> logger,
IProcessorResultCollector collector,
AppDbContext db
)
{
_db = db;
_logger = logger;
_collector = collector;
}
public async Task ProcessAsync(DeviceListModel device, CancellationToken token)
{
// Load SQL Server config for this device
var cfg = await _db.DeviceSqlServer
.AsNoTracking()
.FirstOrDefaultAsync(x => x.DeviceId == device.Id, token);
if (cfg == null)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceSqlServer entry found", device.Id);
return;
}
var parameters = await _db.DeviceParameters
.AsNoTracking()
.Where(x => x.DeviceId == device.Id)
.OrderBy(x => x.ParameterId)
.ToListAsync(token);
if (parameters.Count == 0)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceParameters entry found", device.Id);
return;
}
var amaData = parameters.ToDictionary(r => r.ParameterName, _ => "");
try
{
// Always connect to master first
var masterConnStr = BuildConnectionString(cfg.Host, cfg.DatabaseName, cfg.Username, cfg.Password, cfg.ConnectionOptions);
string targetDatabase;
if (!string.IsNullOrWhiteSpace(cfg.PreferedDatabaseName))
{
// Manual override
targetDatabase = cfg.PreferedDatabaseName;
}
else
{
// Auto-discovery
targetDatabase = await DiscoverAmaDatabaseAsync(device,masterConnStr);
}
if (targetDatabase == null)
{
_logger.LogError("DeviceId {DeviceId}: No Database available.", device.Id);
return;
}
// Now build connection string to the actual AMA database
var amaConnStr = BuildConnectionString(cfg.Host, targetDatabase, cfg.Username, cfg.Password, cfg.ConnectionOptions);
// Execute the AMA query
var rows = await ExecuteAmaQueryAsync(amaConnStr, cfg.Query);
if (rows.Count == 0)
{
_logger.LogWarning("DeviceId {DeviceId}: Empty AMA result received", device.Id);
}
foreach( var row in rows)
amaData[row.Key] = row.Value;
}
catch (TimeoutException)
{
_logger.LogError("DeviceId {DeviceId}: Timeout reading from AMA device", device.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "DeviceId {DeviceId}: Error reading AMA device", device.Id);
}
finally
{
var result = new AmaResult
{
Device = device,
Parameters = amaData
};
var json = JsonSerializer.Serialize(result, new JsonSerializerOptions
{
WriteIndented = true
});
_logger.LogInformation("=== JSON Export ===\n{json}", json);
await _collector.CollectAsync(device, result, token);
}
}
private static string BuildConnectionString(string host, string database, string user, string pass, string options)
{
return $"Data Source={host}\\SQLEXPRESS;Initial Catalog={database};User ID={user};Password={pass};{options}";
}
private async Task<string> DiscoverAmaDatabaseAsync(DeviceListModel device, string masterConnStr)
{
using var conn = new SqlConnection(masterConnStr);
await conn.OpenAsync();
var cmd = conn.CreateCommand();
cmd.CommandText = @"
SELECT name
FROM sys.databases
WHERE name LIKE 'MeasSysDb0504%'
ORDER BY name;
";
var matches = new List<string>();
using (var reader = await cmd.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
matches.Add(reader.GetString(0));
}
if (matches.Count == 0)
{
_logger.LogError("DeviceId {DeviceId}: No AMA database found matching 'MeasSysDb0504%'", device.Id);
return null!;
}
if (matches.Count > 1)
{
_logger.LogWarning("DeviceId {DeviceId}: Multiple AMA databases found", device.Id);
foreach (var m in matches)
{
_logger.LogWarning("DeviceId {DeviceId}: Database=$ - {m}", device.Id, m);
}
}
// Pick the first one
return matches[0];
}
private async Task<Dictionary<string, string>> ExecuteAmaQueryAsync(string connStr, string query)
{
using var conn = new SqlConnection(connStr);
await conn.OpenAsync();
var cmd = conn.CreateCommand();
cmd.CommandText = query;
cmd.CommandType = CommandType.Text;
var result = new Dictionary<string, string>();
using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
var name = reader["ChemCompName"].ToString() ?? "";
var conc = reader["Concentration"].ToString() ?? "";
result[name] = conc;
}
return result;
}
}

View File

@ -0,0 +1,136 @@
using Microsoft.EntityFrameworkCore;
using System.Text.Json;
using Udara.Common.Feature.Csv;
using Udara.Database.App;
using Udara.Database.App.Model;
using Udara.Infrastructure.FileSystem;
using Udara.Infrastructure.FileTransfer;
using Udara.SvcApp.Poll.Processor.Interface;
namespace Udara.SvcApp.Poll.Processor.Mode;
public class CsvResult : IDeviceResult
{
public DeviceListModel Device { get; set; } = default!;
public Dictionary<string, string> Parameters { get; set; } = new();
}
public class CsvProcessor : IDeviceProcessor
{
private readonly AppDbContext _db;
private readonly ILogger<CsvProcessor> _logger;
private readonly IProcessorResultCollector _collector;
private readonly IFileTransfer _fileTransfer;
private readonly IFileReader _fileReader;
private readonly ICsvParser _csvParser;
public CsvProcessor(
AppDbContext db,
ILogger<CsvProcessor> logger,
IProcessorResultCollector collector,
IFileTransfer fileTransfer,
IFileReader fileReader,
ICsvParser csvParser
)
{
_db = db;
_logger = logger;
_collector = collector;
_fileTransfer = fileTransfer;
_fileReader = fileReader;
_csvParser = csvParser;
}
public async Task ProcessAsync(DeviceListModel device, CancellationToken token)
{
var config = await _db.DeviceDatafile
.AsNoTracking()
.FirstOrDefaultAsync(x => x.DeviceId == device.Id, token);
if (config == null)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceDatafile entry found", device.Id);
return;
}
var parameters = await _db.DeviceParameters
.AsNoTracking()
.Where(x => x.DeviceId == device.Id)
.OrderBy(x => x.ParameterId)
.ToListAsync(token);
if (parameters.Count == 0)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceParameters entry found", device.Id);
return;
}
var csvData = parameters.ToDictionary(r => r.ParameterName, _ => "");
try
{
var collected = await _fileTransfer.CollectFilesAsync(
config.ProcessName,
config.TargetDir,
config.FilePattern,
config.FileExtension,
token);
foreach (var file in collected)
{
token.ThrowIfCancellationRequested();
var content = await _fileReader.ReadAllTextAsync(file, token);
if (string.IsNullOrEmpty(content))
continue;
var parsed = _csvParser.Parse(content);
if (!(parsed.Header.Length == 0 || parsed.Rows.Count == 0))
{
var fileData = parsed.Header.Zip(parsed.Rows[0], (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v);
var header = parsed.Header;
var firstRow = parsed.Rows[0];
foreach (var c in fileData)
if (csvData.ContainsKey(c.Key))
csvData[c.Key] = c.Value;
}
else
{
_logger.LogWarning("DeviceId {DeviceId}: CSV file {File} has no usable data", device.Id, file);
continue;
}
await _fileTransfer.ProcessedFilesAsync(file, token);
}
}
catch (TimeoutException)
{
_logger.LogError("DeviceId {DeviceId}: Timeout reading from AIO device", device.Id);
}
catch (Exception ex)
{
_logger.LogError(ex, "DeviceId {DeviceId}: Error processing CSV files", device.Id);
}
finally
{
var result = new CsvResult
{
Device = device,
Parameters = csvData
};
var json = JsonSerializer.Serialize(result, new JsonSerializerOptions
{
WriteIndented = true
});
_logger.LogInformation("=== DeviceId {DeviceId} JSON Export ===\n{json}", device.Id, json);
await _collector.CollectAsync(device, result, token);
}
}
}

View File

@ -0,0 +1,261 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Text.RegularExpressions;
using Udara.Database.App;
using Udara.Database.App.Model;
using Udara.SvcApp.Poll.Processor.Interface;
namespace Udara.SvcApp.Poll.Processor.Mode;
public class ModbusResult : IDeviceResult
{
public DeviceListModel Device { get; set; } = default!;
public Dictionary<string, string> Parameters { get; set; } = new();
public Dictionary<string, string> Flags { get; set; } = new();
}
public class ModbusCommand
{
public string ExecutablePath { get; set; } = string.Empty;
public List<string> Arguments { get; set; } = new();
public string Mode { get; set; } = string.Empty;
public string Target { get; set; } = string.Empty;
public int? SlaveAddress { get; set; }
public int? Reference { get; set; }
public int? Count { get; set; }
public string? DataType { get; set; }
}
public class ModbusCommandBuilder
{
private readonly AppDbContext _db;
private readonly ILogger _logger;
public ModbusCommandBuilder(AppDbContext db, ILogger logger)
{
_db = db;
_logger = logger;
}
public async Task<List<ModbusCommand>> BuildCommands(int deviceId)
{
var rows = await _db.DeviceModbus
.AsNoTracking()
.Where(x => x.DeviceId == deviceId)
.ToListAsync();
var commands = new List<ModbusCommand>();
foreach (var modbus in rows)
{
var mode = modbus.Mode?.Trim().ToLowerInvariant();
if (mode != "tcp" && mode != "rtu")
continue;
if (!modbus.SlaveAddress.HasValue ||
!modbus.Reference.HasValue ||
!modbus.Count.HasValue ||
string.IsNullOrWhiteSpace(modbus.DataType))
continue;
if (mode == "tcp" && (string.IsNullOrWhiteSpace(modbus.Host) || !modbus.TcpPort.HasValue))
continue;
if (mode == "rtu" &&
(string.IsNullOrWhiteSpace(modbus.PortName) ||
!modbus.BaudRate.HasValue ||
!modbus.DataBits.HasValue ||
!modbus.StopBits.HasValue ||
string.IsNullOrWhiteSpace(modbus.Parity)))
continue;
var cmd = new ModbusCommand
{
ExecutablePath = Path.Combine(AppContext.BaseDirectory, "Tools", "mbpoll.exe"),
Mode = mode,
Target = mode == "tcp"
? $"{modbus.Host}:{modbus.TcpPort}"
: modbus.PortName!,
SlaveAddress = modbus.SlaveAddress,
Reference = modbus.Reference,
Count = modbus.Count,
DataType = modbus.DataType
};
var args = new List<string>
{
"-q",
"-1",
"-m", mode,
"-a", modbus.SlaveAddress.Value.ToString(),
"-r", modbus.Reference.Value.ToString(),
"-c", modbus.Count.Value.ToString(),
"-t", modbus.DataType
};
if (mode == "tcp")
{
args.Add("-p");
args.Add(modbus.TcpPort!.Value.ToString());
args.Add(modbus.Host!);
}
else
{
args.Add(modbus.PortName!);
args.Add("-b"); args.Add(modbus.BaudRate!.Value.ToString());
args.Add("-d"); args.Add(modbus.DataBits!.Value.ToString());
args.Add("-s"); args.Add(modbus.StopBits!.Value.ToString());
args.Add("-p"); args.Add(modbus.Parity!);
}
cmd.Arguments = args;
commands.Add(cmd);
}
return commands;
}
}
public class ModbusProcessor : IDeviceProcessor
{
private static readonly Regex _valueRegex = new(@"\[(\d+)\]:\s*(.+)", RegexOptions.Compiled);
private readonly AppDbContext _db;
private readonly ILogger<ModbusProcessor> _logger;
private readonly IProcessorResultCollector _collector;
public ModbusProcessor(
AppDbContext db,
ILogger<ModbusProcessor> logger,
IProcessorResultCollector collector)
{
_db = db;
_logger = logger;
_collector = collector;
}
public async Task ProcessAsync(DeviceListModel device, CancellationToken token)
{
var parameters = await _db.DeviceParameters
.AsNoTracking()
.Where(x => x.DeviceId == device.Id)
.OrderBy(x => x.ParameterId)
.ToListAsync(token);
if (parameters.Count == 0)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceRegisters entry found", device.Id);
return;
}
var flags = await _db.DeviceFlags
.AsNoTracking()
.Where(x => x.DeviceId == device.Id)
.OrderBy(x => x.FlagId)
.ToListAsync(token);
if (flags.Count == 0)
{
_logger.LogError("DeviceId {DeviceId}: No DeviceFlags entry found", device.Id);
return;
}
var deviceParameters = parameters.ToDictionary(p => p.ParameterId, p => p.ParameterName);
var deviceFlags = flags.ToDictionary(f => f.FlagId, f => f.FlagName);
var modbusParameterData = parameters.ToDictionary(p => p.ParameterName, _ => "");
var modbusFlagData = flags.ToDictionary(f => f.FlagName, _ => "");
var builder = new ModbusCommandBuilder(_db, _logger);
var commands = await builder.BuildCommands(device.Id);
foreach (var cmd in commands)
{
if (token.IsCancellationRequested)
break;
var isCoil = IsCoilType(cmd.DataType);
var isReg = IsRegisterType(cmd.DataType);
var lines = await RunMbPollAsync(cmd, token);
foreach (var line in lines)
{
var m = _valueRegex.Match(line);
if (!m.Success)
continue;
var address = int.Parse(m.Groups[1].Value);
var value = m.Groups[2].Value.Trim();
if (isCoil && deviceFlags.TryGetValue(address, out var fname))
modbusFlagData[fname] = value;
if (isReg && deviceParameters.TryGetValue(address, out var pname))
modbusParameterData[pname] = value;
}
await Task.Delay(100, token);
}
var result = new ModbusResult
{
Device = device,
Parameters = modbusParameterData,
Flags = modbusFlagData
};
await _collector.CollectAsync(device, result, token);
}
private static bool IsCoilType(string? t)
{
if (string.IsNullOrWhiteSpace(t)) return false;
t = t.ToLowerInvariant();
return t == "0" || t == "1";
}
private static bool IsRegisterType(string? t)
{
if (string.IsNullOrWhiteSpace(t)) return false;
t = t.ToLowerInvariant();
return t.StartsWith("3") || t.StartsWith("4");
}
private async Task<List<string>> RunMbPollAsync(ModbusCommand cmd, CancellationToken token)
{
var lines = new List<string>();
try
{
var psi = new ProcessStartInfo
{
FileName = cmd.ExecutablePath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
foreach (var arg in cmd.Arguments)
psi.ArgumentList.Add(arg);
using var p = new Process { StartInfo = psi };
p.Start();
var output = await p.StandardOutput.ReadToEndAsync(token);
var error = await p.StandardError.ReadToEndAsync(token);
p.WaitForExit();
foreach (var line in output.Split('\n'))
lines.Add(line.Trim());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error running mbpoll");
}
return lines;
}
}

View File

@ -0,0 +1,172 @@
using System.Collections.Concurrent;
using System.Text.Encodings.Web;
using System.Text.Json;
using Udara.Database.App.Model;
using Udara.Database.Data;
using Udara.Database.Data.Model;
using Udara.SvcApp.Poll.Processor.Interface;
using Udara.SvcApp.Poll.Processor.Mode;
namespace Udara.SvcApp.Poll.Processor;
public class ProcessorResultCollector : IProcessorResultCollector
{
private readonly ILogger<ProcessorResultCollector> _logger;
private readonly DataDbContext _DataDbContext;
private readonly HashSet<int> _expectedDeviceIds = new();
private readonly ConcurrentDictionary<int, DeviceResultSnapshot> _currentBatch = new();
private readonly object _syncRoot = new();
private bool _batchActive;
private DateTime _batchTimestamp;
public ProcessorResultCollector(
ILogger<ProcessorResultCollector> logger,
DataDbContext DataDbContext
)
{
_logger = logger;
_DataDbContext = DataDbContext;
}
public void BeginBatch(IReadOnlyCollection<DeviceListModel> devices, DateTime Timestamp)
{
lock (_syncRoot)
{
_expectedDeviceIds.Clear();
_currentBatch.Clear();
foreach (var device in devices)
_expectedDeviceIds.Add(device.Id);
_batchTimestamp = Timestamp;
_batchActive = _expectedDeviceIds.Count > 0;
_logger.LogInformation(
"Started new raw data batch for {DeviceCount} devices at {Timestamp}",
_expectedDeviceIds.Count,
_batchTimestamp);
}
}
public async Task CollectAsync(DeviceListModel device, IDeviceResult result, CancellationToken token)
{
if (!_batchActive)
{
_logger.LogWarning(
"CollectAsync called for DeviceId {DeviceId} but no active batch is started",
device.Id);
return;
}
var snapshot = MapToSnapshot(device, result);
_currentBatch[device.Id] = snapshot;
_logger.LogInformation(
"Collected result for DeviceId {DeviceId} ({Code})",
device.Id,
device.Code);
if (IsBatchComplete())
{
await PersistCurrentBatchAsync(token);
}
}
private DeviceResultSnapshot MapToSnapshot(DeviceListModel device, IDeviceResult result)
{
var snapshot = new DeviceResultSnapshot
{
DeviceId = device.Id,
Code = device.Code,
Name = device.Name,
Mode = device.Mode,
};
switch (result)
{
//SINI PENTING
case ModbusResult modbus:
snapshot.Flags = modbus.Flags;
snapshot.Parameters = modbus.Parameters;
break;
case AioResult aio:
snapshot.Parameters = aio.Parameters;
break;
case AmaResult ama:
snapshot.Parameters = ama.Parameters;
break;
case AkResult ak:
snapshot.Parameters = ak.Parameters;
break;
case CsvResult csv:
snapshot.Parameters = csv.Parameters;
break;
default:
//snapshot.Values["unknown"] = new Dictionary<string, string>
//{
// ["type"] = result.GetType().Name
//};
break;
}
return snapshot;
}
private bool IsBatchComplete()
{
lock (_syncRoot)
{
if (!_batchActive)
return false;
var complete =
_currentBatch.Count == _expectedDeviceIds.Count &&
_expectedDeviceIds.All(id => _currentBatch.ContainsKey(id));
if (complete)
_batchActive = false;
return complete;
}
}
private async Task PersistCurrentBatchAsync(CancellationToken token)
{
var batch = new DataLoggingBatch
{
Devices = _currentBatch.Values
.OrderBy(x => x.DeviceId)
.ToList()
};
var json = JsonSerializer.Serialize(batch,
new JsonSerializerOptions
{
WriteIndented = false,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}
);
var entry = new RawDataModel
{
Timestamp = _batchTimestamp,
Log = json
};
_DataDbContext.Database.EnsureCreated();
_DataDbContext.RawData.Add(entry);
await _DataDbContext.SaveChangesAsync(token);
_logger.LogInformation(
"Persisted raw data batch with {DeviceCount} devices at {Timestamp}",
batch.Devices.Count,
_batchTimestamp);
}
}

Some files were not shown because too many files have changed in this diff Show More