WIP: Begins work on pdf client.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ DerivedData/
|
|||||||
.swift-version
|
.swift-version
|
||||||
node_modules/
|
node_modules/
|
||||||
tailwindcss
|
tailwindcss
|
||||||
|
.envrc
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ let package = Package(
|
|||||||
.library(name: "ApiController", targets: ["ApiController"]),
|
.library(name: "ApiController", targets: ["ApiController"]),
|
||||||
.library(name: "AuthClient", targets: ["AuthClient"]),
|
.library(name: "AuthClient", targets: ["AuthClient"]),
|
||||||
.library(name: "DatabaseClient", targets: ["DatabaseClient"]),
|
.library(name: "DatabaseClient", targets: ["DatabaseClient"]),
|
||||||
|
.library(name: "PdfClient", targets: ["PdfClient"]),
|
||||||
.library(name: "ProjectClient", targets: ["ProjectClient"]),
|
.library(name: "ProjectClient", targets: ["ProjectClient"]),
|
||||||
.library(name: "ManualDCore", targets: ["ManualDCore"]),
|
.library(name: "ManualDCore", targets: ["ManualDCore"]),
|
||||||
.library(name: "ManualDClient", targets: ["ManualDClient"]),
|
.library(name: "ManualDClient", targets: ["ManualDClient"]),
|
||||||
@@ -75,6 +76,14 @@ let package = Package(
|
|||||||
.product(name: "Vapor", package: "vapor"),
|
.product(name: "Vapor", package: "vapor"),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
.target(
|
||||||
|
name: "PdfClient",
|
||||||
|
dependencies: [
|
||||||
|
.target(name: "ManualDCore"),
|
||||||
|
.product(name: "Dependencies", package: "swift-dependencies"),
|
||||||
|
.product(name: "DependenciesMacros", package: "swift-dependencies"),
|
||||||
|
]
|
||||||
|
),
|
||||||
.target(
|
.target(
|
||||||
name: "ProjectClient",
|
name: "ProjectClient",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import Fluent
|
|||||||
import FluentSQLiteDriver
|
import FluentSQLiteDriver
|
||||||
import ManualDCore
|
import ManualDCore
|
||||||
import NIOSSL
|
import NIOSSL
|
||||||
|
import ProjectClient
|
||||||
import Vapor
|
import Vapor
|
||||||
import VaporElementary
|
import VaporElementary
|
||||||
@preconcurrency import VaporRouting
|
@preconcurrency import VaporRouting
|
||||||
@@ -111,6 +112,8 @@ extension SiteRoute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension DuctSizes: Content {}
|
||||||
|
|
||||||
@Sendable
|
@Sendable
|
||||||
private func siteHandler(
|
private func siteHandler(
|
||||||
request: Request,
|
request: Request,
|
||||||
@@ -118,6 +121,7 @@ private func siteHandler(
|
|||||||
) async throws -> any AsyncResponseEncodable {
|
) async throws -> any AsyncResponseEncodable {
|
||||||
@Dependency(\.apiController) var apiController
|
@Dependency(\.apiController) var apiController
|
||||||
@Dependency(\.viewController) var viewController
|
@Dependency(\.viewController) var viewController
|
||||||
|
@Dependency(\.projectClient) var projectClient
|
||||||
|
|
||||||
switch route {
|
switch route {
|
||||||
case .api(let route):
|
case .api(let route):
|
||||||
@@ -125,6 +129,11 @@ private func siteHandler(
|
|||||||
case .health:
|
case .health:
|
||||||
return HTTPStatus.ok
|
return HTTPStatus.ok
|
||||||
case .view(let route):
|
case .view(let route):
|
||||||
|
// FIX: Remove.
|
||||||
|
if route == .test {
|
||||||
|
let projectID = UUID(uuidString: "E796C96C-F527-4753-A00A-EBCF25630663")!
|
||||||
|
return try await projectClient.calculateDuctSizes(projectID)
|
||||||
|
}
|
||||||
return try await viewController.respond(route: route, request: request)
|
return try await viewController.respond(route: route, request: request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ extension DependencyValues {
|
|||||||
@DependencyClient
|
@DependencyClient
|
||||||
public struct ManualDClient: Sendable {
|
public struct ManualDClient: Sendable {
|
||||||
public var ductSize: @Sendable (DuctSizeRequest) async throws -> DuctSizeResponse
|
public var ductSize: @Sendable (DuctSizeRequest) async throws -> DuctSizeResponse
|
||||||
public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRateResponse
|
public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRate
|
||||||
public var totalEquivalentLength: @Sendable (TotalEquivalentLengthRequest) async throws -> Int
|
public var totalEquivalentLength: @Sendable (TotalEquivalentLengthRequest) async throws -> Int
|
||||||
public var rectangularSize:
|
public var rectangularSize:
|
||||||
@Sendable (RectangularSizeRequest) async throws -> RectangularSizeResponse
|
@Sendable (RectangularSizeRequest) async throws -> RectangularSizeResponse
|
||||||
@@ -28,7 +28,7 @@ extension ManualDClient: DependencyKey {
|
|||||||
let totalComponentLosses = request.componentPressureLosses.total
|
let totalComponentLosses = request.componentPressureLosses.total
|
||||||
let availableStaticPressure = request.externalStaticPressure - totalComponentLosses
|
let availableStaticPressure = request.externalStaticPressure - totalComponentLosses
|
||||||
let frictionRate = availableStaticPressure * 100.0 / Double(request.totalEffectiveLength)
|
let frictionRate = availableStaticPressure * 100.0 / Double(request.totalEffectiveLength)
|
||||||
return .init(availableStaticPressure: availableStaticPressure, frictionRate: frictionRate)
|
return .init(availableStaticPressure: availableStaticPressure, value: frictionRate)
|
||||||
},
|
},
|
||||||
totalEquivalentLength: { request in
|
totalEquivalentLength: { request in
|
||||||
let trunkLengths = request.trunkLengths.reduce(0) { $0 + $1 }
|
let trunkLengths = request.trunkLengths.reduce(0) { $0 + $1 }
|
||||||
|
|||||||
14
Sources/ManualDCore/FrictionRate.swift
Normal file
14
Sources/ManualDCore/FrictionRate.swift
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/// Holds onto values returned when calculating the design
|
||||||
|
/// friction rate for a project.
|
||||||
|
public struct FrictionRate: Codable, Equatable, Sendable {
|
||||||
|
public let availableStaticPressure: Double
|
||||||
|
public let value: Double
|
||||||
|
|
||||||
|
public init(
|
||||||
|
availableStaticPressure: Double,
|
||||||
|
value: Double
|
||||||
|
) {
|
||||||
|
self.availableStaticPressure = availableStaticPressure
|
||||||
|
self.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Sources/PdfClient/Interface.swift
Normal file
47
Sources/PdfClient/Interface.swift
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import Dependencies
|
||||||
|
import DependenciesMacros
|
||||||
|
import ManualDCore
|
||||||
|
|
||||||
|
@DependencyClient
|
||||||
|
public struct PdfClient: Sendable {
|
||||||
|
public var markdown: @Sendable (Request) async throws -> String
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PdfClient: TestDependencyKey {
|
||||||
|
public static let testValue = Self()
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PdfClient {
|
||||||
|
|
||||||
|
public struct Request: Codable, Equatable, Sendable {
|
||||||
|
|
||||||
|
public let project: Project
|
||||||
|
public let componentLosses: [ComponentPressureLoss]
|
||||||
|
public let ductSizes: DuctSizes
|
||||||
|
public let equipmentInfo: EquipmentInfo
|
||||||
|
public let maxSupplyTEL: EffectiveLength
|
||||||
|
public let maxReturnTEL: EffectiveLength
|
||||||
|
public let designFrictionRate: FrictionRate
|
||||||
|
public let projectSHR: Double
|
||||||
|
|
||||||
|
public init(
|
||||||
|
project: Project,
|
||||||
|
componentLosses: [ComponentPressureLoss],
|
||||||
|
ductSizes: DuctSizes,
|
||||||
|
equipmentInfo: EquipmentInfo,
|
||||||
|
maxSupplyTEL: EffectiveLength,
|
||||||
|
maxReturnTEL: EffectiveLength,
|
||||||
|
designFrictionRate: FrictionRate,
|
||||||
|
projectSHR: Double
|
||||||
|
) {
|
||||||
|
self.project = project
|
||||||
|
self.componentLosses = componentLosses
|
||||||
|
self.ductSizes = ductSizes
|
||||||
|
self.equipmentInfo = equipmentInfo
|
||||||
|
self.maxSupplyTEL = maxSupplyTEL
|
||||||
|
self.maxReturnTEL = maxReturnTEL
|
||||||
|
self.designFrictionRate = designFrictionRate
|
||||||
|
self.projectSHR = projectSHR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Sources/PdfClient/Request+markdown.swift
Normal file
42
Sources/PdfClient/Request+markdown.swift
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import ManualDCore
|
||||||
|
|
||||||
|
extension PdfClient.Request {
|
||||||
|
|
||||||
|
func toMarkdown() -> String {
|
||||||
|
var retval = """
|
||||||
|
# Duct Calc
|
||||||
|
|
||||||
|
**Name:** \(project.name)
|
||||||
|
**Address:** \(project.streetAddress)
|
||||||
|
\(project.city), \(project.state) \(project.zipCode)
|
||||||
|
|
||||||
|
## Equipment
|
||||||
|
|
||||||
|
| | Value |
|
||||||
|
|-----------------|---------------------------------|
|
||||||
|
| Static Pressure | \(equipmentInfo.staticPressure) |
|
||||||
|
| Heating CFM | \(equipmentInfo.heatingCFM) |
|
||||||
|
| Cooling CFM | \(equipmentInfo.coolingCFM) |
|
||||||
|
|
||||||
|
## Friction Rate
|
||||||
|
|
||||||
|
| | Value |
|
||||||
|
|-----------------|---------------------------------|
|
||||||
|
|
||||||
|
"""
|
||||||
|
for row in componentLosses {
|
||||||
|
retval = """
|
||||||
|
\(retval)
|
||||||
|
\(componentLossRow(row))
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval
|
||||||
|
}
|
||||||
|
|
||||||
|
func componentLossRow(_ row: ComponentPressureLoss) -> String {
|
||||||
|
return """
|
||||||
|
| \(row.name) | \(row.value) |
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,12 +58,12 @@ extension ProjectClient {
|
|||||||
|
|
||||||
public let componentLosses: [ComponentPressureLoss]
|
public let componentLosses: [ComponentPressureLoss]
|
||||||
public let equivalentLengths: EffectiveLength.MaxContainer
|
public let equivalentLengths: EffectiveLength.MaxContainer
|
||||||
public let frictionRate: ManualDClient.FrictionRateResponse?
|
public let frictionRate: FrictionRate?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
componentLosses: [ComponentPressureLoss],
|
componentLosses: [ComponentPressureLoss],
|
||||||
equivalentLengths: EffectiveLength.MaxContainer,
|
equivalentLengths: EffectiveLength.MaxContainer,
|
||||||
frictionRate: ManualDClient.FrictionRateResponse? = nil
|
frictionRate: FrictionRate? = nil
|
||||||
) {
|
) {
|
||||||
self.componentLosses = componentLosses
|
self.componentLosses = componentLosses
|
||||||
self.equivalentLengths = equivalentLengths
|
self.equivalentLengths = equivalentLengths
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ extension ViewController.Request {
|
|||||||
|
|
||||||
switch route {
|
switch route {
|
||||||
case .test:
|
case .test:
|
||||||
// let projectID = UUID(uuidString: "A9C20153-E2E5-4C65-B33F-4D8A29C63A7A")!
|
// let projectID = UUID(uuidString: "E796C96C-F527-4753-A00A-EBCF25630663")!
|
||||||
return await view {
|
return await view {
|
||||||
await ResultView {
|
await ResultView {
|
||||||
|
|
||||||
@@ -372,7 +372,7 @@ extension SiteRoute.View.ProjectRoute.FrictionRateRoute {
|
|||||||
FrictionRateView(
|
FrictionRateView(
|
||||||
componentLosses: losses,
|
componentLosses: losses,
|
||||||
equivalentLengths: lengths,
|
equivalentLengths: lengths,
|
||||||
frictionRateResponse: frictionRate
|
frictionRate: frictionRate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,7 +430,7 @@ extension SiteRoute.View.ProjectRoute.ComponentLossRoute {
|
|||||||
FrictionRateView(
|
FrictionRateView(
|
||||||
componentLosses: response.componentLosses,
|
componentLosses: response.componentLosses,
|
||||||
equivalentLengths: response.equivalentLengths,
|
equivalentLengths: response.equivalentLengths,
|
||||||
frictionRateResponse: response.frictionRate
|
frictionRate: response.frictionRate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,37 +9,33 @@ struct FrictionRateView: HTML, Sendable {
|
|||||||
|
|
||||||
let componentLosses: [ComponentPressureLoss]
|
let componentLosses: [ComponentPressureLoss]
|
||||||
let equivalentLengths: EffectiveLength.MaxContainer
|
let equivalentLengths: EffectiveLength.MaxContainer
|
||||||
let frictionRateResponse: ManualDClient.FrictionRateResponse?
|
let frictionRate: FrictionRate?
|
||||||
|
|
||||||
private var availableStaticPressure: Double? {
|
private var availableStaticPressure: Double? {
|
||||||
frictionRateResponse?.availableStaticPressure
|
frictionRate?.availableStaticPressure
|
||||||
}
|
|
||||||
|
|
||||||
private var frictionRateDesignValue: Double? {
|
|
||||||
frictionRateResponse?.frictionRate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var shouldShowBadges: Bool {
|
private var shouldShowBadges: Bool {
|
||||||
frictionRateDesignValue != nil || availableStaticPressure != nil
|
frictionRate != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private var badgeColor: String {
|
private var badgeColor: String {
|
||||||
let base = "badge-info"
|
let base = "badge-info"
|
||||||
guard let frictionRateDesignValue else { return base }
|
guard let frictionRate = frictionRate?.value else { return base }
|
||||||
if frictionRateDesignValue >= 0.18 || frictionRateDesignValue <= 0.02 {
|
if frictionRate >= 0.18 || frictionRate <= 0.02 {
|
||||||
return "badge-error"
|
return "badge-error"
|
||||||
}
|
}
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
private var showHighErrors: Bool {
|
private var showHighErrors: Bool {
|
||||||
guard let frictionRateDesignValue else { return false }
|
guard let frictionRate = frictionRate?.value else { return false }
|
||||||
return frictionRateDesignValue >= 0.18
|
return frictionRate >= 0.18
|
||||||
}
|
}
|
||||||
|
|
||||||
private var showLowErrors: Bool {
|
private var showLowErrors: Bool {
|
||||||
guard let frictionRateDesignValue else { return false }
|
guard let frictionRate = frictionRate?.value else { return false }
|
||||||
return frictionRateDesignValue <= 0.02
|
return frictionRate <= 0.02
|
||||||
}
|
}
|
||||||
|
|
||||||
private var showNoComponentLossesError: Bool {
|
private var showNoComponentLossesError: Bool {
|
||||||
@@ -47,7 +43,7 @@ struct FrictionRateView: HTML, Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var showIncompleteSectionsError: Bool {
|
private var showIncompleteSectionsError: Bool {
|
||||||
availableStaticPressure == nil || frictionRateDesignValue == nil
|
availableStaticPressure == nil || frictionRate?.value == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private var hasAlerts: Bool {
|
private var hasAlerts: Bool {
|
||||||
@@ -68,11 +64,11 @@ struct FrictionRateView: HTML, Sendable {
|
|||||||
div(.class("space-y-2 justify-end font-bold text-lg")) {
|
div(.class("space-y-2 justify-end font-bold text-lg")) {
|
||||||
if shouldShowBadges {
|
if shouldShowBadges {
|
||||||
|
|
||||||
if let frictionRateDesignValue {
|
if let frictionRate = frictionRate?.value {
|
||||||
LabeledContent {
|
LabeledContent {
|
||||||
span { "Friction Rate Design Value" }
|
span { "Friction Rate Design Value" }
|
||||||
} content: {
|
} content: {
|
||||||
Badge(number: frictionRateDesignValue, digits: 2)
|
Badge(number: frictionRate, digits: 2)
|
||||||
.attributes(.class("\(badgeColor) badge-lg"))
|
.attributes(.class("\(badgeColor) badge-lg"))
|
||||||
.bold()
|
.bold()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ extension ManualDClient {
|
|||||||
equipmentInfo: EquipmentInfo?,
|
equipmentInfo: EquipmentInfo?,
|
||||||
componentLosses: [ComponentPressureLoss],
|
componentLosses: [ComponentPressureLoss],
|
||||||
effectiveLength: EffectiveLength.MaxContainer
|
effectiveLength: EffectiveLength.MaxContainer
|
||||||
) async throws -> FrictionRateResponse? {
|
) async throws -> FrictionRate? {
|
||||||
guard let staticPressure = equipmentInfo?.staticPressure else {
|
guard let staticPressure = equipmentInfo?.staticPressure else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
359
ductsizes.json
Normal file
359
ductsizes.json
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
{
|
||||||
|
"trunks": [
|
||||||
|
{
|
||||||
|
"trunk": {
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663",
|
||||||
|
"type": "supply",
|
||||||
|
"name": "West",
|
||||||
|
"id": "AFBC5264-8129-4383-97D8-F44CF5258A53",
|
||||||
|
"rooms": [
|
||||||
|
{
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 4567,
|
||||||
|
"id": "FA2F107F-5DF0-4D69-B231-DE3C6EF64134",
|
||||||
|
"registerCount": 3,
|
||||||
|
"heatingLoad": 9876,
|
||||||
|
"updatedAt": "2026-01-17T16:51:33Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:33Z",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663",
|
||||||
|
"name": "Kitchen"
|
||||||
|
},
|
||||||
|
"registers": [1, 2, 3]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 4567,
|
||||||
|
"id": "9A01CEE8-6A4B-4299-9353-58AFAD042903",
|
||||||
|
"registerCount": 3,
|
||||||
|
"heatingLoad": 9876,
|
||||||
|
"updatedAt": "2026-01-17T16:51:21Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:21Z",
|
||||||
|
"name": "Master",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663"
|
||||||
|
},
|
||||||
|
"registers": [1, 2, 3]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"height": 8
|
||||||
|
},
|
||||||
|
"ductSize": {
|
||||||
|
"height": 8,
|
||||||
|
"roundSize": 12.3660960368007,
|
||||||
|
"width": 19,
|
||||||
|
"velocity": 737,
|
||||||
|
"finalSize": 14,
|
||||||
|
"flexSize": 14,
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 787.278055507671
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trunk": {
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663",
|
||||||
|
"name": "East",
|
||||||
|
"id": "C6A21594-0A28-4A20-BC15-628502010201",
|
||||||
|
"type": "supply",
|
||||||
|
"height": 8,
|
||||||
|
"rooms": [
|
||||||
|
{
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 1234,
|
||||||
|
"id": "2420F9C7-0FCA-4E92-BAC9-8A054CB3201B",
|
||||||
|
"registerCount": 1,
|
||||||
|
"heatingLoad": 4567,
|
||||||
|
"updatedAt": "2026-01-17T16:51:10Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:10Z",
|
||||||
|
"name": "Entry",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663"
|
||||||
|
},
|
||||||
|
"registers": [1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 1234,
|
||||||
|
"id": "449FE324-2ACF-4C12-83A3-EB86FD45A991",
|
||||||
|
"registerCount": 2,
|
||||||
|
"heatingLoad": 4567,
|
||||||
|
"updatedAt": "2026-01-17T16:51:02Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:02Z",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663",
|
||||||
|
"name": "Bed-1"
|
||||||
|
},
|
||||||
|
"registers": [1, 2]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ductSize": {
|
||||||
|
"height": 8,
|
||||||
|
"roundSize": 8.39504804369037,
|
||||||
|
"width": 8,
|
||||||
|
"velocity": 643,
|
||||||
|
"flexSize": 10,
|
||||||
|
"finalSize": 9,
|
||||||
|
"designCFM": {
|
||||||
|
"heating": {
|
||||||
|
"_0": 284.587689538185
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trunk": {
|
||||||
|
"name": "Main",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663",
|
||||||
|
"id": "C65863A0-D2EE-4D90-8C71-B1FD2454A8DF",
|
||||||
|
"type": "return",
|
||||||
|
"rooms": [
|
||||||
|
{
|
||||||
|
"registers": [1, 2, 3],
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 4567,
|
||||||
|
"id": "FA2F107F-5DF0-4D69-B231-DE3C6EF64134",
|
||||||
|
"registerCount": 3,
|
||||||
|
"heatingLoad": 9876,
|
||||||
|
"updatedAt": "2026-01-17T16:51:33Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:33Z",
|
||||||
|
"name": "Kitchen",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"registers": [1, 2, 3],
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 4567,
|
||||||
|
"id": "9A01CEE8-6A4B-4299-9353-58AFAD042903",
|
||||||
|
"registerCount": 3,
|
||||||
|
"heatingLoad": 9876,
|
||||||
|
"updatedAt": "2026-01-17T16:51:21Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:21Z",
|
||||||
|
"name": "Master",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"registers": [1],
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 1234,
|
||||||
|
"id": "2420F9C7-0FCA-4E92-BAC9-8A054CB3201B",
|
||||||
|
"registerCount": 1,
|
||||||
|
"heatingLoad": 4567,
|
||||||
|
"updatedAt": "2026-01-17T16:51:10Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:10Z",
|
||||||
|
"name": "Entry",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"registers": [1, 2],
|
||||||
|
"room": {
|
||||||
|
"coolingTotal": 1234,
|
||||||
|
"id": "449FE324-2ACF-4C12-83A3-EB86FD45A991",
|
||||||
|
"registerCount": 2,
|
||||||
|
"heatingLoad": 4567,
|
||||||
|
"updatedAt": "2026-01-17T16:51:02Z",
|
||||||
|
"createdAt": "2026-01-17T16:51:02Z",
|
||||||
|
"name": "Bed-1",
|
||||||
|
"projectID": "E796C96C-F527-4753-A00A-EBCF25630663"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ductSize": {
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 1000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 13.539327773393,
|
||||||
|
"velocity": 935,
|
||||||
|
"finalSize": 14,
|
||||||
|
"flexSize": 16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rooms": [
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 521,
|
||||||
|
"flexSize": 6,
|
||||||
|
"designCFM": {
|
||||||
|
"heating": {
|
||||||
|
"_0": 71.1469223845461
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 4.95724506597333,
|
||||||
|
"finalSize": 5
|
||||||
|
},
|
||||||
|
"heatingCFM": 71.1469223845461,
|
||||||
|
"roomRegister": 1,
|
||||||
|
"heatingLoad": 2283.5,
|
||||||
|
"roomName": "Bed-1-1",
|
||||||
|
"roomID": "449FE324-2ACF-4C12-83A3-EB86FD45A991",
|
||||||
|
"coolingLoad": 512.11,
|
||||||
|
"coolingCFM": 53.1804861230822
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 521,
|
||||||
|
"flexSize": 6,
|
||||||
|
"designCFM": {
|
||||||
|
"heating": {
|
||||||
|
"_0": 71.1469223845461
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 4.95724506597333,
|
||||||
|
"finalSize": 5
|
||||||
|
},
|
||||||
|
"heatingCFM": 71.1469223845461,
|
||||||
|
"roomRegister": 2,
|
||||||
|
"heatingLoad": 2283.5,
|
||||||
|
"roomName": "Bed-1-2",
|
||||||
|
"roomID": "449FE324-2ACF-4C12-83A3-EB86FD45A991",
|
||||||
|
"coolingLoad": 512.11,
|
||||||
|
"coolingCFM": 53.1804861230822
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 532,
|
||||||
|
"flexSize": 7,
|
||||||
|
"designCFM": {
|
||||||
|
"heating": {
|
||||||
|
"_0": 142.293844769092
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 6.4510704920341,
|
||||||
|
"finalSize": 7
|
||||||
|
},
|
||||||
|
"heatingCFM": 142.293844769092,
|
||||||
|
"roomRegister": 1,
|
||||||
|
"heatingLoad": 4567,
|
||||||
|
"roomName": "Entry-1",
|
||||||
|
"roomID": "2420F9C7-0FCA-4E92-BAC9-8A054CB3201B",
|
||||||
|
"coolingLoad": 1024.22,
|
||||||
|
"coolingCFM": 106.360972246164
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 490,
|
||||||
|
"flexSize": 7,
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 131.213009251279
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 6.25641154872314,
|
||||||
|
"finalSize": 7
|
||||||
|
},
|
||||||
|
"heatingCFM": 102.568718410303,
|
||||||
|
"roomRegister": 1,
|
||||||
|
"heatingLoad": 3292,
|
||||||
|
"roomName": "Kitchen-1",
|
||||||
|
"roomID": "FA2F107F-5DF0-4D69-B231-DE3C6EF64134",
|
||||||
|
"coolingLoad": 1263.53666666667,
|
||||||
|
"coolingCFM": 131.213009251279
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 490,
|
||||||
|
"flexSize": 7,
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 131.213009251279
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 6.25641154872314,
|
||||||
|
"finalSize": 7
|
||||||
|
},
|
||||||
|
"heatingCFM": 102.568718410303,
|
||||||
|
"roomRegister": 2,
|
||||||
|
"heatingLoad": 3292,
|
||||||
|
"roomName": "Kitchen-2",
|
||||||
|
"roomID": "FA2F107F-5DF0-4D69-B231-DE3C6EF64134",
|
||||||
|
"coolingLoad": 1263.53666666667,
|
||||||
|
"coolingCFM": 131.213009251279
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 490,
|
||||||
|
"flexSize": 7,
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 131.213009251279
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 6.25641154872314,
|
||||||
|
"finalSize": 7
|
||||||
|
},
|
||||||
|
"heatingCFM": 102.568718410303,
|
||||||
|
"roomRegister": 3,
|
||||||
|
"heatingLoad": 3292,
|
||||||
|
"roomName": "Kitchen-3",
|
||||||
|
"roomID": "FA2F107F-5DF0-4D69-B231-DE3C6EF64134",
|
||||||
|
"coolingLoad": 1263.53666666667,
|
||||||
|
"coolingCFM": 131.213009251279
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 490,
|
||||||
|
"flexSize": 7,
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 131.213009251279
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 6.25641154872314,
|
||||||
|
"finalSize": 7
|
||||||
|
},
|
||||||
|
"heatingCFM": 102.568718410303,
|
||||||
|
"roomRegister": 1,
|
||||||
|
"heatingLoad": 3292,
|
||||||
|
"roomName": "Master-1",
|
||||||
|
"roomID": "9A01CEE8-6A4B-4299-9353-58AFAD042903",
|
||||||
|
"coolingLoad": 1263.53666666667,
|
||||||
|
"coolingCFM": 131.213009251279
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 490,
|
||||||
|
"flexSize": 7,
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 131.213009251279
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 6.25641154872314,
|
||||||
|
"finalSize": 7
|
||||||
|
},
|
||||||
|
"heatingCFM": 102.568718410303,
|
||||||
|
"roomRegister": 2,
|
||||||
|
"heatingLoad": 3292,
|
||||||
|
"roomName": "Master-2",
|
||||||
|
"roomID": "9A01CEE8-6A4B-4299-9353-58AFAD042903",
|
||||||
|
"coolingLoad": 1263.53666666667,
|
||||||
|
"coolingCFM": 131.213009251279
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ductSize": {
|
||||||
|
"velocity": 490,
|
||||||
|
"flexSize": 7,
|
||||||
|
"designCFM": {
|
||||||
|
"cooling": {
|
||||||
|
"_0": 131.213009251279
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roundSize": 6.25641154872314,
|
||||||
|
"finalSize": 7
|
||||||
|
},
|
||||||
|
"heatingCFM": 102.568718410303,
|
||||||
|
"roomRegister": 3,
|
||||||
|
"heatingLoad": 3292,
|
||||||
|
"roomName": "Master-3",
|
||||||
|
"roomID": "9A01CEE8-6A4B-4299-9353-58AFAD042903",
|
||||||
|
"coolingLoad": 1263.53666666667,
|
||||||
|
"coolingCFM": 131.213009251279
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user