feat: Initial filter pressure drop views, calculations need implemented.

This commit is contained in:
2025-03-02 21:51:52 -05:00
parent a8022ec80a
commit 67488e06a9
17 changed files with 610 additions and 97 deletions

View File

@@ -1,8 +1,10 @@
public enum ClimateZone: String, Codable, Equatable, Sendable {
case dry
public enum ClimateZone: String, CaseIterable, Codable, Equatable, Sendable {
// NOTE: Keep in this order.
case hotHumid
case marine
case moist
case dry
case marine
public var zoneIdentifiers: [String] {
switch self {
@@ -26,6 +28,6 @@ public enum ClimateZone: String, Codable, Equatable, Sendable {
}
public var label: String {
return "\(rawValue.capitalized) (\(zoneIdentifiers.joined(separator: ",")))"
return "\(self == .hotHumid ? "Hot Humid" : rawValue.capitalized) (\(zoneIdentifiers.joined(separator: ", ")))"
}
}

View File

@@ -4,20 +4,25 @@ public enum FilterPressureDrop {
Calculate filter pressure drop and sizing based on system requirements.
"""
public enum Mode: String, CaseIterable, Codable, Equatable, Sendable {
case basic
case fanLaw
}
public enum Request: Codable, Equatable, Sendable {
case basic(Basic)
case fanLaw(FanLaw)
public struct Basic: Codable, Equatable, Sendable {
let systemSize: HVACSystemSize
let systemSize: Double
let climateZone: ClimateZone
let filterType: FilterType
let filterWidth: Double
let filterHeight: Double
public init(
systemSize: HVACSystemSize,
systemSize: Double,
climateZone: ClimateZone,
filterType: FilterPressureDrop.FilterType,
filterWidth: Double,
@@ -58,22 +63,30 @@ public enum FilterPressureDrop {
}
}
public enum Result: Codable, Equatable, Sendable {
public enum Response: Codable, Equatable, Sendable {
case basic(Basic)
case fanLaw(FanLaw)
public struct Basic: Codable, Equatable, Sendable {
let filterArea: Double
let feetPerMinute: Double
let initialPressureDrop: Double
let maxPressureDrop: Double
public let filterArea: Double
public let feetPerMinute: Double
public let initialPressureDrop: Double
public let maxPressureDrop: Double
public let warnings: [String]
public init(filterArea: Double, feetPerMinute: Double, initialPressureDrop: Double, maxPressureDrop: Double) {
public init(
filterArea: Double,
feetPerMinute: Double,
initialPressureDrop: Double,
maxPressureDrop: Double,
warnings: [String]
) {
self.filterArea = filterArea
self.feetPerMinute = feetPerMinute
self.initialPressureDrop = initialPressureDrop
self.maxPressureDrop = maxPressureDrop
self.warnings = warnings
}
}
@@ -98,7 +111,7 @@ public enum FilterPressureDrop {
}
}
public enum FilterType: String, Codable, Equatable, Sendable {
public enum FilterType: String, CaseIterable, Codable, Equatable, Sendable {
case fiberglass
case pleatedBasic
case pleatedBetter
@@ -114,3 +127,34 @@ public enum FilterPressureDrop {
}
}
}
#if DEBUG
public extension FilterPressureDrop.Response {
static func mock(mode: FilterPressureDrop.Mode) -> Self {
switch mode {
case .basic:
return .basic(.init(
filterArea: 3.47,
feetPerMinute: 230,
initialPressureDrop: 0.2,
maxPressureDrop: 0.15,
warnings: [
"""
Intial pressure drop is more than 50% of maximum allowable.
Consider using a larger filter or different type with lower intial pressure drop.
"""
]
))
case .fanLaw:
return .fanLaw(.init(
predictedPressureDrop: 0.127,
velocityRatio: 1.13,
pressureRatio: 1.27,
faceVelocity: 259
))
}
}
}
#endif

View File

@@ -1,4 +1,4 @@
public enum HVACSystemSize: Double, Codable, Equatable, Sendable {
public enum HVACSystemSize: Double, CaseIterable, Codable, Equatable, Sendable {
case one = 1
case oneAndAHalf = 1.5
case two = 2

View File

@@ -13,6 +13,10 @@ public enum SiteRoute: Equatable, Sendable {
Route(.case(Self.api)) {
Api.router
}
Route(.case(Self.health)) {
Path { "health" }
Method.get
}
Route(.case(Self.view)) {
View.router
}
@@ -26,6 +30,7 @@ public extension SiteRoute {
case calculateAtticVentilation(AtticVentilation.Request)
case calculateCapacitor(Capacitor.Request)
case calculateDehumidifierSize(DehumidifierSize.Request)
case calculateFilterPressureDrop(FilterPressureDrop.Request)
case calculateHVACSystemPerformance(HVACSystemPerformance.Request)
case calculateMoldRisk(MoldRisk.Request)
case calculateRoomPressure(RoomPressure.Request)
@@ -53,6 +58,16 @@ public extension SiteRoute {
Method.post
Body(.json(DehumidifierSize.Request.self))
}
Route(.case(Self.calculateFilterPressureDrop)) {
Path { "api"; "v1"; "calculateFilterPressureDrop" }
Method.post
OneOf {
Body(.json(FilterPressureDrop.Request.Basic.self))
.map(.case(FilterPressureDrop.Request.basic))
Body(.json(FilterPressureDrop.Request.FanLaw.self))
.map(.case(FilterPressureDrop.Request.fanLaw))
}
}
Route(.case(Self.calculateHVACSystemPerformance)) {
Path { "api"; "v1"; "calculateHVACSystemPerformance" }
Method.post
@@ -84,6 +99,7 @@ public extension SiteRoute {
case atticVentilation(AtticVentilation)
case capacitor(Capacitor)
case dehumidifierSize(DehumidifierSize)
case filterPressureDrop(FilterPressureDrop)
case hvacSystemPerformance(HVACSystemPerformance)
case moldRisk(MoldRisk)
case roomPressure(RoomPressure)
@@ -101,6 +117,9 @@ public extension SiteRoute {
Route(.case(Self.dehumidifierSize)) {
DehumidifierSize.router
}
Route(.case(Self.filterPressureDrop)) {
FilterPressureDrop.router
}
Route(.case(Self.hvacSystemPerformance)) {
HVACSystemPerformance.router
}
@@ -213,6 +232,53 @@ public extension SiteRoute {
}
}
public enum FilterPressureDrop: Equatable, Sendable {
case index(mode: Routes.FilterPressureDrop.Mode? = nil)
case submit(Routes.FilterPressureDrop.Request)
public static let index = Self.index()
static let rootPath = "filter-pressure-drop"
public static let router = OneOf {
Route(.case(Self.index)) {
Path { rootPath }
Method.get
Query {
Optionally { Field("mode") { Routes.FilterPressureDrop.Mode.parser() } }
}
}
Route(.case(Self.submit)) {
Path { rootPath }
Method.post
Body {
OneOf {
FormData {
Field("systemSize") { Double.parser() }
Field("climateZone") { ClimateZone.parser() }
Field("filterType") { Routes.FilterPressureDrop.FilterType.parser() }
Field("filterWidth") { Double.parser() }
Field("filterHeight") { Double.parser() }
}
.map(.memberwise(Routes.FilterPressureDrop.Request.Basic.init))
.map(.case(Routes.FilterPressureDrop.Request.basic))
FormData {
Field("filterWidth") { Double.parser() }
Field("filterHeight") { Double.parser() }
Field("filterDepth") { Double.parser() }
Field("ratedAirflow") { Double.parser() }
Field("ratedPressureDrop") { Double.parser() }
Field("designAirflow") { Double.parser() }
}
.map(.memberwise(Routes.FilterPressureDrop.Request.FanLaw.init))
.map(.case(Routes.FilterPressureDrop.Request.fanLaw))
}
}
}
}
}
public enum HVACSystemPerformance: Equatable, Sendable {
case index
case submit(Routes.HVACSystemPerformance.Request)