feat: Adds psychrometrics calculator.
This commit is contained in:
106
Sources/Routes/Models/PsychrometricProperties.swift
Normal file
106
Sources/Routes/Models/PsychrometricProperties.swift
Normal file
@@ -0,0 +1,106 @@
|
||||
import CasePaths
|
||||
import PsychrometricClient
|
||||
@preconcurrency import URLRouting
|
||||
|
||||
public enum Psychrometrics {
|
||||
|
||||
public static let description = """
|
||||
Calculate the psychrometric properties of air based on temperature and humidity readings.
|
||||
"""
|
||||
public struct Request: Codable, Equatable, Sendable {
|
||||
|
||||
// public let mode: Mode
|
||||
public let temperature: Double
|
||||
public let humidity: Double
|
||||
public let altitude: Double?
|
||||
|
||||
public init(temperature: Double, humidity: Double, altitude: Double? = nil) {
|
||||
self.temperature = temperature
|
||||
self.humidity = humidity
|
||||
self.altitude = altitude
|
||||
}
|
||||
|
||||
public enum FieldKey: String {
|
||||
case temperature
|
||||
case humidity
|
||||
case altitude
|
||||
}
|
||||
}
|
||||
|
||||
public struct Response: Codable, Equatable, Sendable {
|
||||
public let properties: PsychrometricProperties
|
||||
public let warnings: [String]
|
||||
|
||||
public init(properties: PsychrometricProperties, warnings: [String]) {
|
||||
self.properties = properties
|
||||
self.warnings = warnings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Router
|
||||
|
||||
public extension SiteRoute.View {
|
||||
|
||||
enum Psychrometrics: Equatable, Sendable {
|
||||
|
||||
case index
|
||||
case submit(Routes.Psychrometrics.Request)
|
||||
|
||||
typealias Key = Routes.Psychrometrics.Request.FieldKey
|
||||
static let rootPath = "psychrometric-properties"
|
||||
|
||||
public static let router = OneOf {
|
||||
Route(.case(Self.index)) {
|
||||
Path { rootPath }
|
||||
Method.get
|
||||
}
|
||||
Route(.case(Self.submit)) {
|
||||
Path { rootPath }
|
||||
Method.post
|
||||
Body {
|
||||
FormData {
|
||||
Field(Key.temperature) {
|
||||
Double.parser()
|
||||
}
|
||||
Field(Key.humidity) {
|
||||
Double.parser()
|
||||
}
|
||||
Optionally {
|
||||
Field(Key.altitude) {
|
||||
Double.parser()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.map(.memberwise(Routes.Psychrometrics.Request.init))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public extension Psychrometrics.Response {
|
||||
static let mock = Self(
|
||||
properties: .init(
|
||||
absoluteHumidity: 91.4,
|
||||
atmosphericPressure: 0.3,
|
||||
degreeOfSaturation: 0.66,
|
||||
density: 0.07,
|
||||
dewPoint: 64.3,
|
||||
dryBulb: 76,
|
||||
enthalpy: 32.33,
|
||||
grainsOfMoisture: 91.4,
|
||||
humidityRatio: 0.01,
|
||||
relativeHumidity: 67,
|
||||
specificVolume: 13.78,
|
||||
vaporPressure: 0.3,
|
||||
wetBulb: 67.7,
|
||||
units: .imperial
|
||||
),
|
||||
warnings: [
|
||||
"Test warning."
|
||||
]
|
||||
)
|
||||
}
|
||||
#endif
|
||||
@@ -4,6 +4,9 @@ import Foundation
|
||||
import PsychrometricClient
|
||||
@preconcurrency import URLRouting
|
||||
|
||||
// FIX: Move Routers into their respective model files, to reduce the size / complexity of this file
|
||||
// and keep them closer to where changes may need made.
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
public enum SiteRoute: Equatable, Sendable {
|
||||
|
||||
@@ -105,6 +108,7 @@ public extension SiteRoute {
|
||||
case heatingBalancePoint(HeatingBalancePoint)
|
||||
case hvacSystemPerformance(HVACSystemPerformance)
|
||||
case moldRisk(MoldRisk)
|
||||
case psychrometrics(Self.Psychrometrics)
|
||||
case roomPressure(RoomPressure)
|
||||
|
||||
public static let router = OneOf {
|
||||
@@ -132,6 +136,9 @@ public extension SiteRoute {
|
||||
Route(.case(Self.moldRisk)) {
|
||||
MoldRisk.router
|
||||
}
|
||||
Route(.case(Self.psychrometrics)) {
|
||||
Self.Psychrometrics.router
|
||||
}
|
||||
Route(.case(Self.roomPressure)) {
|
||||
RoomPressure.router
|
||||
}
|
||||
@@ -460,6 +467,7 @@ public extension SiteRoute {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
40
Sources/Routes/URLRoutingExtensions.swift
Normal file
40
Sources/Routes/URLRoutingExtensions.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
import URLRouting
|
||||
|
||||
// Allow the use of a field key enum as the `name` parameter, to avoid
|
||||
// stringly type name fields.
|
||||
public extension Field {
|
||||
|
||||
@inlinable
|
||||
init<Key>(
|
||||
_ name: Key,
|
||||
default defaultValue: Value.Output? = nil,
|
||||
@ParserBuilder<Substring> _ value: () -> Value
|
||||
) where Key: RawRepresentable, Key.RawValue == String {
|
||||
self.init(name.rawValue, default: defaultValue, value)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
init<Key, C>(
|
||||
_ name: Key,
|
||||
_ value: C,
|
||||
default defaultValue: Value.Output? = nil,
|
||||
) where Key: RawRepresentable, Key.RawValue == String,
|
||||
Value == Parsers.MapConversion<Parsers.ReplaceError<Rest<Substring>>, C>
|
||||
{
|
||||
self.init(name.rawValue, value, default: defaultValue)
|
||||
}
|
||||
|
||||
@inlinable
|
||||
init<Key>(
|
||||
_ name: Key,
|
||||
default defaultValue: Value.Output? = nil
|
||||
)
|
||||
where
|
||||
Key: RawRepresentable, Key.RawValue == String,
|
||||
Value == Parsers.MapConversion<
|
||||
Parsers.ReplaceError<Rest<Substring>>, Conversions.SubstringToString
|
||||
>
|
||||
{
|
||||
self.init(name.rawValue, default: defaultValue)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user