diff --git a/Dockerfile.dev b/Dockerfile.dev
index 856b0c5..8fa1b21 100644
--- a/Dockerfile.dev
+++ b/Dockerfile.dev
@@ -1,5 +1,3 @@
-# NOTE: Builds currently fail when building in release mode.
-
ARG SWIFT_MODE="debug"
# ================================
# Build image
@@ -29,70 +27,6 @@ COPY . .
# Build the application, with optimizations, with static linking, and using jemalloc
# N.B.: The static version of jemalloc is incompatible with the static Swift runtime.
-RUN --mount=type=cache,target=/build/.build swift build \
- -c ${SWIFT_MODE} \
- --product App \
- --static-swift-stdlib \
- -Xswiftc -g
+RUN swift build
-# Switch to the staging area
-WORKDIR /staging
-
-# Copy main executable to staging area
-RUN --mount=type=cache,target=/build/.build cp \
- "$(swift build --package-path /build -c ${SWIFT_MODE} --show-bin-path)/App" ./
-
-# Copy static swift backtracer binary to staging area
-RUN --mount=type=cache,target=/build/.build \
- cp "/usr/libexec/swift/linux/swift-backtrace-static" ./
-
-# Copy resources bundled by SPM to staging area
-RUN --mount=type=cache,target=/build/.build \
- find -L "$(swift build --package-path /build -c ${SWIFT_MODE} --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \;
-
-# Copy any resources from the public directory and views directory if the directories exist
-# Ensure that by default, neither the directory nor any of its contents are writable.
-RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true
-RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true
-
-# ================================
-# Run image
-# ================================
-FROM ubuntu:noble
-
-# Make sure all system packages are up to date, and install only essential packages.
-RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \
- && apt-get -q update \
- && apt-get -q dist-upgrade -y \
- && apt-get -q install -y \
- libjemalloc2 \
- ca-certificates \
- tzdata \
-# If your app or its dependencies import FoundationNetworking, also install `libcurl4`.
- libcurl4 \
- curl \
-# If your app or its dependencies import FoundationXML, also install `libxml2`.
- # libxml2 \
- && rm -r /var/lib/apt/lists/*
-
-# Create a vapor user and group with /app as its home directory
-RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor
-
-# Switch to the new home directory
-WORKDIR /app
-
-# Copy built executable and any staged resources from builder
-COPY --from=build --chown=vapor:vapor /staging /app
-
-# Provide configuration needed by the built-in crash reporter and some sensible default behaviors.
-ENV SWIFT_BACKTRACE=enable=yes,sanitize=yes,threads=all,images=all,interactive=no,swift-backtrace=./swift-backtrace-static
-
-# Ensure all further commands run as the vapor user
-USER vapor:vapor
-
-# Let Docker bind to port 8080
-EXPOSE 8080
-
-# Start the Vapor service when the image is run, default to listening on 8080 in production environment
-ENTRYPOINT ["./App"]
-CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"]
+CMD ["swift", "test"]
diff --git a/Tests/ViewControllerTests/ViewControllerTests.swift b/Tests/ViewControllerTests/ViewControllerTests.swift
index 386520c..08d30d2 100644
--- a/Tests/ViewControllerTests/ViewControllerTests.swift
+++ b/Tests/ViewControllerTests/ViewControllerTests.swift
@@ -3,6 +3,7 @@ import Elementary
import HTMLSnapshotTesting
import Logging
import OrderedCollections
+import PsychrometricClientLive
import Routes
import SnapshotTesting
import Testing
@@ -14,11 +15,13 @@ struct ViewControllerTests {
let record = SnapshotTestingConfiguration.Record.missing
let logger = Logger(label: "ViewControllerTests")
+ // swiftlint:disable function_body_length
@Test
func snapShotTests() async throws {
try await withSnapshotTesting(record: record) {
try await withDependencies {
$0.viewController = .liveValue
+ $0.psychrometricClient = .liveValue
} operation: {
@Dependency(\.viewController) var viewController
@@ -33,15 +36,18 @@ struct ViewControllerTests {
atticDewpoint: 76,
atticFloorArea: 1234
))),
+
// Capacitor
.capacitor(.index),
.capacitor(.index(mode: .size)),
.capacitor(.index(mode: .test)),
.capacitor(.submit(.size(.init(runningAmps: 10.7, lineVoltage: 243, powerFactor: 0.86)))),
.capacitor(.submit(.test(.init(startWindingAmps: 4.3, runToCommonVoltage: 343)))),
+
// Dehumidifier Sizing
.dehumidifierSize(.index),
.dehumidifierSize(.submit(.init(latentLoad: 3443, temperature: 76, humidity: 67))),
+
// Filter Pressure Drop
.filterPressureDrop(.index),
.filterPressureDrop(.index(mode: .basic)),
@@ -60,7 +66,66 @@ struct ViewControllerTests {
ratedAirflow: 800,
ratedPressureDrop: 0.1,
designAirflow: 900
+ )))),
+
+ // Heating Balance Point
+ .heatingBalancePoint(.index),
+ .heatingBalancePoint(.heatLossFields(mode: .estimated)),
+ .heatingBalancePoint(.heatLossFields(mode: .known)),
+ .heatingBalancePoint(.submit(.economic(.init(
+ fuelType: .propane,
+ fuelCostPerUnit: 2.43,
+ fuelAFUE: 90,
+ costPerKW: 0.13
+ )))),
+ .heatingBalancePoint(.submit(.thermal(.init(
+ systemSize: 2,
+ capacityAt47: 24600,
+ capacityAt17: 15100,
+ heatingDesignTemperature: 5,
+ buildingHeatLoss: .known(btu: 45667),
+ climateZone: .five
+ )))),
+
+ // HVAC System Performance
+ .hvacSystemPerformance(.index),
+ .hvacSystemPerformance(.submit(.init(
+ altitude: 800,
+ airflow: 800,
+ returnAirTemperature: 76,
+ returnAirHumidity: 67,
+ supplyAirTemperature: 56,
+ supplyAirHumidity: 89,
+ systemSize: 2
+ ))),
+
+ // Mold risk
+ .moldRisk(.index),
+ .moldRisk(.submit(.init(temperature: 76, humidity: 67))),
+
+ // Psychrometrics
+ .psychrometrics(.index),
+ .psychrometrics(.submit(.init(temperature: 76, humidity: 67, altitude: 800))),
+
+ // Room pressures
+ .roomPressure(.index),
+ .roomPressure(.index(mode: .measuredPressure)),
+ .roomPressure(.submit(.knownAirflow(.init(
+ targetRoomPressure: 3,
+ doorWidth: 30,
+ doorHeight: 86,
+ doorUndercut: 1,
+ supplyAirflow: 200,
+ preferredGrilleHeight: .fourteen
+ )))),
+ .roomPressure(.submit(.measuredPressure(.init(
+ measuredRoomPressure: 4,
+ doorWidth: 30,
+ doorHeight: 86,
+ doorUndercut: 1,
+ preferredGrilleHeight: .fourteen
))))
+
])
for route in arguments {
@@ -71,6 +136,8 @@ struct ViewControllerTests {
}
}
+ // swiftlint:enable function_body_length
+
}
private extension ViewController {
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.15.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.15.html
new file mode 100644
index 0000000..4ddf5be
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.15.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
Balance Point - Thermal
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.16.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.16.html
new file mode 100644
index 0000000..214c152
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.16.html
@@ -0,0 +1,41 @@
+
+
+
Heat Loss - Estimated
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.17.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.17.html
new file mode 100644
index 0000000..c2f0b33
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.17.html
@@ -0,0 +1,29 @@
+
+
+
Heat Loss - Known
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.18.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.18.html
new file mode 100644
index 0000000..5c5e3b0
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.18.html
@@ -0,0 +1,51 @@
+
+
+
Results
+
+
+
+
+
+
+
+
Economic Balance Point
+
+
+
+
Balance Point
+
-13°F
+
+
+
+
+
Electric Cost
+
$38.1/ MMBTU
+
+
+
+
+
Fuel Cost
+
$29.56/ MMBTU
+
+
+
+
+
+
COP at Balance Point
+
1.29
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.19.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.19.html
new file mode 100644
index 0000000..a38745c
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.19.html
@@ -0,0 +1,57 @@
+
+
+
Results
+
+
+
+
+
+
+
+
Thermal Balance Point
+
+
+
+
Balance Point
+
36.9°F
+
+
+
+
+
Heat Loss - Known
+
45,667BTU/h
+
+
+
+
+
Heating Design Temperature
+
5°F
+
+
+
+
+
Capacity @ 47°
+
24,600BTU/h
+
+
+
+
+
Capacity @ 17°
+
15,100BTU/h
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.20.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.20.html
new file mode 100644
index 0000000..dd6e788
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.20.html
@@ -0,0 +1,82 @@
+
+
+
+
+
HVAC System Performance
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.21.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.21.html
new file mode 100644
index 0000000..92cc75f
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.21.html
@@ -0,0 +1,95 @@
+
+
+
Results
+
+
+
+
+
Total Capacity
+
2.9Tons
+
35,396.9 BTU/h
+
+
+
Sensible Capacity
+
1.4Tons
+
17,280 BTU/h
+
+
+
Latent Capacity
+
1.5Tons
+
18,116.9 BTU/h
+
+
+
+
System Performance Metrics
+
+
+
+ Airflow per Ton
+
400CFM/ton
+
+
+
+ Temperature Split
+
20°F
+
+
Target: 20.83 °F
+
+
+
+
+ Moisture Removal
+
2gal/h
+
+
+ Sensible Heat Ratio
+
0.5%
+
+
+
+
+ Warning:
+
+
Low sensible heat ratio may indicate excessive dehumidification or low airflow.
+
+
+
+
+
+
Return Air Properties
+
+
Dew Point: 64.3 °F
+
Wet Bulb: 67.64 °F
+
Enthalpy: 32.75 Btu/lb
+
Density: 0.07 lb/ft³
+
Vapor Pressure: 0.3 psi
+
Specific Volume: 14.2
+
Absolute Humidity: 94.18 gr/ft³
+
Humidity Ratio: 0.01
+
Degree of Saturation: 0.66
+
+
+
+
Supply Air Properties
+
+
Dew Point: 52.87 °F
+
Wet Bulb: 54.01 °F
+
Enthalpy: 22.92 Btu/lb
+
Density: 0.07 lb/ft³
+
Vapor Pressure: 0.2 psi
+
Specific Volume: 13.57
+
Absolute Humidity: 61.47 gr/ft³
+
Humidity Ratio: 0.01
+
Degree of Saturation: 0.89
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.22.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.22.html
new file mode 100644
index 0000000..a6b9b12
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.22.html
@@ -0,0 +1,35 @@
+
+
+
+
+
Mold Risk Calculator
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.23.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.23.html
new file mode 100644
index 0000000..51968c5
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.23.html
@@ -0,0 +1,60 @@
+
+
+
Results
+
+
+
+
+
+
+
+
+
+ Risk Level: Moderate
+
+
Estimated Days to Mold Growth: 30 days
+
+
+
+ Recommendations:
+
+
+
Improve ventilation to reduce moisture accumulation
+
Inspect for and repair any water leaks or intrusion
+
+
+
+
+
+
Psychrometric Properties
+
+
Dew Point: 64.3 °F
+
Wet Bulb: 67.7 °F
+
Enthalpy: 32.33 Btu/lb
+
Density: 0.07 lb/ft³
+
Vapor Pressure: 0.3 psi
+
Specific Volume: 13.78
+
Absolute Humidity: 91.4 gr/ft³
+
Humidity Ratio: 0.01
+
Degree of Saturation: 0.66
+
+
+
+
Note:
+
+ These calculations are based on typical indoor conditions and common mold species. Actual mold growth can
+ vary based on surface materials, air movement, and other environmental factors. Always address moisture
+ issues promptly and consult professionals for severe cases.
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.24.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.24.html
new file mode 100644
index 0000000..033bb4b
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.24.html
@@ -0,0 +1,47 @@
+
+
+
+
+
Psychrometric Properties
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.25.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.25.html
new file mode 100644
index 0000000..8bb211a
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.25.html
@@ -0,0 +1,58 @@
+
+
+
Results
+
+
+
+
+
+
+
+
Psychrometrics
+
+
+
+
+
Dew Point
+
64.3°F
+
+
+
+
+
Enthalpy
+
32.8Btu/lb
+
+
+
+
+
Wet Bulb
+
67.6°F
+
+
+
+
+
Other Properties
+
+
Density: 0.07 lb/ft³
+
Vapor Pressure: 0.3 psi
+
Specific Volume: 14.2
+
Absolute Humidity: 94.18 gr/ft³
+
Humidity Ratio: 0.01
+
Degree of Saturation: 0.66
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.26.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.26.html
new file mode 100644
index 0000000..3809874
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.26.html
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
Room Pressure Calculator - Known Airflow
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.27.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.27.html
new file mode 100644
index 0000000..deab6b8
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.27.html
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
Room Pressure Calculator - Measured Pressure
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.28.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.28.html
new file mode 100644
index 0000000..ba0ed0b
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.28.html
@@ -0,0 +1,34 @@
+
+
+
Results
+
+
+
+
+
Return / Transfer Grille
+
Standard Size: 14" x 14"
+
Required Net Free Area: 0.5 in2
+
Note: Select a grille with at least 0.5 in2 net free area.
+
+
+
Return / Transfer Duct
+
Standard Size:9"
+
Air Velocity:452.7 FPM
+
+
+
+
+
Note:
+
+ Calculations are based on a target velocity of 400 FPM for return/transfer air paths.
+ The required net free area is the minimum needed - select a grille that meets or exceeds this value.
+ Verify manufacturer specifications for actual net free area of selected grilles.
+
+
+
\ No newline at end of file
diff --git a/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.29.html b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.29.html
new file mode 100644
index 0000000..6c23cbe
--- /dev/null
+++ b/Tests/ViewControllerTests/__Snapshots__/ViewControllerTests/snapShotTests.29.html
@@ -0,0 +1,34 @@
+
+
+
Results
+
+
+
+
+
Return / Transfer Grille
+
Standard Size: 14" x 14"
+
Required Net Free Area: 0.5 in2
+
Note: Select a grille with at least 0.5 in2 net free area.
+
+
+
Return / Transfer Duct
+
Standard Size:9"
+
Air Velocity:440.7 FPM
+
+
+
+
+
Note:
+
+ Calculations are based on a target velocity of 400 FPM for return/transfer air paths.
+ The required net free area is the minimum needed - select a grille that meets or exceeds this value.
+ Verify manufacturer specifications for actual net free area of selected grilles.
+
+
+
\ No newline at end of file
diff --git a/justfile b/justfile
index 549aa4a..235cbbb 100644
--- a/justfile
+++ b/justfile
@@ -27,3 +27,7 @@ push-image:
build-docker-production:
@docker build --platform "linux/amd64" -t {{docker_registiry}}/{{docker_image}}:{{docker_tag}} .
+
+test-docker:
+ @docker build --tag {{docker_image}}:test --file Dockerfile.dev . \
+ && docker run --interactive --rm {{docker_image}}:test swift test