feat: Begins more work on async integration
This commit is contained in:
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
root = true
|
||||
|
||||
[*.swift]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
trim_trailing_whitespace = true
|
||||
1
.swiftformat
Normal file
1
.swiftformat
Normal file
@@ -0,0 +1 @@
|
||||
--self init-only
|
||||
@@ -6,21 +6,21 @@ import NIO
|
||||
import Psychrometrics
|
||||
|
||||
public struct Client {
|
||||
|
||||
|
||||
/// Add the publish listeners to the MQTT Broker, to be notified of published changes.
|
||||
public var addListeners: () -> Void
|
||||
|
||||
|
||||
/// Connect to the MQTT Broker.
|
||||
public var connect: () -> EventLoopFuture<Void>
|
||||
|
||||
|
||||
public var publishSensor: (SensorPublishRequest) -> EventLoopFuture<Void>
|
||||
|
||||
|
||||
/// Subscribe to appropriate topics / events.
|
||||
public var subscribe: () -> EventLoopFuture<Void>
|
||||
|
||||
|
||||
/// Disconnect and close the connection to the MQTT Broker.
|
||||
public var shutdown: () -> EventLoopFuture<Void>
|
||||
|
||||
|
||||
public init(
|
||||
addListeners: @escaping () -> Void,
|
||||
connect: @escaping () -> EventLoopFuture<Void>,
|
||||
@@ -34,9 +34,9 @@ public struct Client {
|
||||
self.shutdown = shutdown
|
||||
self.subscribe = subscribe
|
||||
}
|
||||
|
||||
|
||||
public enum SensorPublishRequest {
|
||||
case mixed(State.Sensors.TemperatureHumiditySensor<State.Sensors.Mixed>)
|
||||
case mixed(State.Sensors.TemperatureHumiditySensor<State.Sensors.MixedAir>)
|
||||
case postCoil(State.Sensors.TemperatureHumiditySensor<State.Sensors.PostCoil>)
|
||||
case `return`(State.Sensors.TemperatureHumiditySensor<State.Sensors.Return>)
|
||||
case supply(State.Sensors.TemperatureHumiditySensor<State.Sensors.Supply>)
|
||||
|
||||
@@ -61,7 +61,7 @@ public class AsyncClient {
|
||||
tlsConfiguration: nil,
|
||||
webSocketURLPath: nil
|
||||
)
|
||||
self.client = .init(
|
||||
self.client = MQTTClient(
|
||||
host: envVars.host,
|
||||
identifier: envVars.identifier,
|
||||
eventLoopGroupProvider: .shared(Self.eventLoopGroup),
|
||||
|
||||
@@ -3,7 +3,7 @@ import Psychrometrics
|
||||
|
||||
// TODO: Make this a struct, then create a Store class that holds the state??
|
||||
public final class State {
|
||||
|
||||
|
||||
public var altitude: Length
|
||||
public var sensors: Sensors
|
||||
public var units: PsychrometricEnvironment.Units {
|
||||
@@ -11,7 +11,7 @@ public final class State {
|
||||
PsychrometricEnvironment.shared.units = units
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public init(
|
||||
altitude: Length = .seaLevel,
|
||||
sensors: Sensors = .init(),
|
||||
@@ -21,16 +21,16 @@ public final class State {
|
||||
self.sensors = sensors
|
||||
self.units = units
|
||||
}
|
||||
|
||||
|
||||
public struct Sensors: Equatable {
|
||||
|
||||
public var mixedAirSensor: TemperatureHumiditySensor<Mixed>
|
||||
|
||||
public var mixedAirSensor: TemperatureHumiditySensor<MixedAir>
|
||||
public var postCoilSensor: TemperatureHumiditySensor<PostCoil>
|
||||
public var returnAirSensor: TemperatureHumiditySensor<Return>
|
||||
public var supplyAirSensor: TemperatureHumiditySensor<Supply>
|
||||
|
||||
|
||||
public init(
|
||||
mixedAirSensor: TemperatureHumiditySensor<Mixed> = .init(),
|
||||
mixedAirSensor: TemperatureHumiditySensor<MixedAir> = .init(),
|
||||
postCoilSensor: TemperatureHumiditySensor<PostCoil> = .init(),
|
||||
returnAirSensor: TemperatureHumiditySensor<Return> = .init(),
|
||||
supplyAirSensor: TemperatureHumiditySensor<Supply> = .init()
|
||||
@@ -40,7 +40,7 @@ public final class State {
|
||||
self.returnAirSensor = returnAirSensor
|
||||
self.supplyAirSensor = supplyAirSensor
|
||||
}
|
||||
|
||||
|
||||
public var needsProcessed: Bool {
|
||||
mixedAirSensor.needsProcessed
|
||||
|| postCoilSensor.needsProcessed
|
||||
@@ -51,15 +51,15 @@ public final class State {
|
||||
}
|
||||
|
||||
extension State.Sensors {
|
||||
|
||||
|
||||
public struct TemperatureHumiditySensor<Location>: Equatable {
|
||||
|
||||
|
||||
@TrackedChanges
|
||||
public var temperature: Temperature?
|
||||
|
||||
|
||||
@TrackedChanges
|
||||
public var humidity: RelativeHumidity?
|
||||
|
||||
|
||||
public var needsProcessed: Bool {
|
||||
get { $temperature.needsProcessed || $humidity.needsProcessed }
|
||||
set {
|
||||
@@ -67,7 +67,7 @@ extension State.Sensors {
|
||||
$humidity.needsProcessed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func dewPoint(units: PsychrometricEnvironment.Units? = nil) -> DewPoint? {
|
||||
guard let temperature = temperature,
|
||||
let humidity = humidity,
|
||||
@@ -76,7 +76,7 @@ extension State.Sensors {
|
||||
else { return nil }
|
||||
return .init(dryBulb: temperature, humidity: humidity, units: units)
|
||||
}
|
||||
|
||||
|
||||
public func enthalpy(altitude: Length, units: PsychrometricEnvironment.Units? = nil) -> EnthalpyOf<MoistAir>? {
|
||||
guard let temperature = temperature,
|
||||
let humidity = humidity,
|
||||
@@ -85,7 +85,7 @@ extension State.Sensors {
|
||||
else { return nil }
|
||||
return .init(dryBulb: temperature, humidity: humidity, altitude: altitude, units: units)
|
||||
}
|
||||
|
||||
|
||||
public init(
|
||||
temperature: Temperature? = nil,
|
||||
humidity: RelativeHumidity? = nil,
|
||||
@@ -95,9 +95,9 @@ extension State.Sensors {
|
||||
self._humidity = .init(wrappedValue: humidity, needsProcessed: needsProcessed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Temperature / Humidity Sensor Location Namespaces
|
||||
public enum Mixed { }
|
||||
public enum MixedAir { }
|
||||
public enum PostCoil { }
|
||||
public enum Return { }
|
||||
public enum Supply { }
|
||||
|
||||
65
Sources/Models/TemperatureAndHumiditySensor.swift
Normal file
65
Sources/Models/TemperatureAndHumiditySensor.swift
Normal file
@@ -0,0 +1,65 @@
|
||||
import Psychrometrics
|
||||
|
||||
public struct TemperatureAndHumiditySensor: Equatable, Identifiable {
|
||||
/// The identifier of the sensor, same as the location.
|
||||
public var id: Location { location }
|
||||
|
||||
public let altitude: Length
|
||||
|
||||
/// The location identifier of the sensor
|
||||
public let location: Location
|
||||
|
||||
/// The current temperature value of the sensor.
|
||||
@TrackedChanges
|
||||
public var temperature: Temperature?
|
||||
|
||||
/// The current humidity value of the sensor.
|
||||
@TrackedChanges
|
||||
public var humidity: RelativeHumidity?
|
||||
|
||||
/// The psychrometric units of the sensor.
|
||||
public let units: PsychrometricEnvironment.Units
|
||||
|
||||
public init(
|
||||
location: Location,
|
||||
altitude: Length = .feet(800.0),
|
||||
temperature: Temperature? = nil,
|
||||
humidity: RelativeHumidity? = nil,
|
||||
needsProcessed: Bool = false,
|
||||
units: PsychrometricEnvironment.Units = .imperial
|
||||
) {
|
||||
self.altitude = altitude
|
||||
self.location = location
|
||||
self._temperature = .init(wrappedValue: temperature, needsProcessed: needsProcessed)
|
||||
self._humidity = .init(wrappedValue: humidity, needsProcessed: needsProcessed)
|
||||
self.units = units
|
||||
}
|
||||
|
||||
/// The calculated dew-point temperature of the sensor.
|
||||
public var dewPoint: DewPoint? {
|
||||
guard let temperature = temperature,
|
||||
let humidity = humidity,
|
||||
!temperature.rawValue.isNaN,
|
||||
!humidity.rawValue.isNaN
|
||||
else { return nil }
|
||||
return .init(dryBulb: temperature, humidity: humidity, units: units)
|
||||
}
|
||||
|
||||
/// Check whether any of the sensor values have changed and need processed.
|
||||
public var needsProcessed: Bool {
|
||||
get { $temperature.needsProcessed || $humidity.needsProcessed }
|
||||
set {
|
||||
$temperature.needsProcessed = newValue
|
||||
$humidity.needsProcessed = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the different locations of a temperature and humidity sensor, which can
|
||||
/// be used to derive the topic to both listen and publish new values to.
|
||||
public enum Location: String, Equatable, Hashable {
|
||||
case mixedAir = "mixed-air"
|
||||
case postCoil = "post-coil"
|
||||
case `return`
|
||||
case supply
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
|
||||
/// A container for all the different topics that are needed by the application.
|
||||
/// A container for all the different MQTT topics that are needed by the application.
|
||||
public struct Topics: Codable, Equatable {
|
||||
|
||||
|
||||
/// The command topics the application can publish to.
|
||||
public var commands: Commands
|
||||
|
||||
|
||||
/// The sensor topics the application can read from / write to.
|
||||
public var sensors: Sensors
|
||||
|
||||
|
||||
/// The set point topics the application can read set point values from.
|
||||
public var setPoints: SetPoints
|
||||
|
||||
|
||||
/// The state topics the application can read state values from.
|
||||
public var states: States
|
||||
|
||||
|
||||
/// Create the topics required by the application.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -32,17 +32,17 @@ public struct Topics: Codable, Equatable {
|
||||
self.setPoints = setPoints
|
||||
self.states = states
|
||||
}
|
||||
|
||||
|
||||
/// Represents the sensor topics.
|
||||
public struct Sensors: Codable, Equatable {
|
||||
|
||||
public var mixedAirSensor: TemperatureAndHumiditySensor<State.Sensors.Mixed>
|
||||
|
||||
public var mixedAirSensor: TemperatureAndHumiditySensor<State.Sensors.MixedAir>
|
||||
public var postCoilSensor: TemperatureAndHumiditySensor<State.Sensors.PostCoil>
|
||||
public var returnAirSensor: TemperatureAndHumiditySensor<State.Sensors.Return>
|
||||
public var supplyAirSensor: TemperatureAndHumiditySensor<State.Sensors.Supply>
|
||||
|
||||
|
||||
public init(
|
||||
mixedAirSensor: TemperatureAndHumiditySensor<State.Sensors.Mixed> = .default(location: "mixed=air"),
|
||||
mixedAirSensor: TemperatureAndHumiditySensor<State.Sensors.MixedAir> = .default(location: "mixed-air"),
|
||||
postCoilSensor: TemperatureAndHumiditySensor<State.Sensors.PostCoil> = .default(location: "post-coil"),
|
||||
returnAirSensor: TemperatureAndHumiditySensor<State.Sensors.Return> = .default(location: "return"),
|
||||
supplyAirSensor: TemperatureAndHumiditySensor<State.Sensors.Supply> = .default(location: "supply")
|
||||
@@ -52,13 +52,13 @@ public struct Topics: Codable, Equatable {
|
||||
self.returnAirSensor = returnAirSensor
|
||||
self.supplyAirSensor = supplyAirSensor
|
||||
}
|
||||
|
||||
|
||||
public struct TemperatureAndHumiditySensor<Location>: Codable, Equatable {
|
||||
public var temperature: String
|
||||
public var humidity: String
|
||||
public var dewPoint: String
|
||||
public var enthalpy: String
|
||||
|
||||
|
||||
/// Create a new sensor topic container.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -78,16 +78,16 @@ public struct Topics: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A container for set point related topics used by the application.
|
||||
public struct SetPoints: Codable, Equatable {
|
||||
|
||||
|
||||
/// The topic for the humidify set point.
|
||||
public var humidify: Humidify
|
||||
|
||||
|
||||
/// The topics for dehumidification set points.
|
||||
public var dehumidify: Dehumidify
|
||||
|
||||
|
||||
/// Create a new set point topic container.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -100,16 +100,16 @@ public struct Topics: Codable, Equatable {
|
||||
self.humidify = humidify
|
||||
self.dehumidify = dehumidify
|
||||
}
|
||||
|
||||
|
||||
/// A container for the humidification set point topics used by the application.
|
||||
public struct Humidify: Codable, Equatable {
|
||||
|
||||
|
||||
/// The topic for dew point control mode set point.
|
||||
public var dewPoint: String
|
||||
|
||||
|
||||
/// The topic for relative humidity control mode set point.
|
||||
public var relativeHumidity: String
|
||||
|
||||
|
||||
/// Create a new container for the humidification set point topics.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -123,22 +123,22 @@ public struct Topics: Codable, Equatable {
|
||||
self.relativeHumidity = relativeHumidity
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A container for dehumidifcation set point topics.
|
||||
public struct Dehumidify: Codable, Equatable {
|
||||
|
||||
|
||||
/// A low setting for dew point control modes.
|
||||
public var lowDewPoint: String
|
||||
|
||||
|
||||
/// A high setting for dew point control modes.
|
||||
public var highDewPoint: String
|
||||
|
||||
|
||||
/// A low setting for relative humidity control modes.
|
||||
public var lowRelativeHumidity: String
|
||||
|
||||
|
||||
/// A high setting for relative humidity control modes.
|
||||
public var highRelativeHumidity: String
|
||||
|
||||
|
||||
/// Create a new container for dehumidification set point topics.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -159,16 +159,16 @@ public struct Topics: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A container for control state topics used by the application.
|
||||
public struct States: Codable, Equatable {
|
||||
|
||||
|
||||
/// The topic for the control mode.
|
||||
public var mode: String
|
||||
|
||||
|
||||
/// The relay state topics.
|
||||
public var relays: Relays
|
||||
|
||||
|
||||
/// Create a new container for control state topics.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -180,19 +180,19 @@ public struct Topics: Codable, Equatable {
|
||||
self.mode = mode
|
||||
self.relays = relays
|
||||
}
|
||||
|
||||
|
||||
/// A container for reading the current state of a relay.
|
||||
public struct Relays: Codable, Equatable {
|
||||
|
||||
|
||||
/// The dehumidification stage-1 relay topic.
|
||||
public var dehumdification1: String
|
||||
|
||||
|
||||
/// The dehumidification stage-2 relay topic.
|
||||
public var dehumidification2: String
|
||||
|
||||
|
||||
/// The humidification relay topic.
|
||||
public var humdification: String
|
||||
|
||||
|
||||
/// Create a new container for relay state topics.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -210,13 +210,13 @@ public struct Topics: Codable, Equatable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A container for commands topics that the application can publish to.
|
||||
public struct Commands: Codable, Equatable {
|
||||
|
||||
|
||||
/// The relay command topics.
|
||||
public var relays: Relays
|
||||
|
||||
|
||||
/// Create a new command topics container.
|
||||
///
|
||||
/// - Parameters:
|
||||
@@ -224,19 +224,19 @@ public struct Topics: Codable, Equatable {
|
||||
public init(relays: Relays = .init()) {
|
||||
self.relays = relays
|
||||
}
|
||||
|
||||
|
||||
/// A container for relay command topics used by the application.
|
||||
public struct Relays: Codable, Equatable {
|
||||
|
||||
|
||||
/// The dehumidification stage-1 relay topic.
|
||||
public var dehumidification1: String
|
||||
|
||||
|
||||
/// The dehumidification stage-2 relay topic.
|
||||
public var dehumidification2: String
|
||||
|
||||
|
||||
/// The humidification relay topic.
|
||||
public var humidification: String
|
||||
|
||||
|
||||
/// Create a new container for commanding relays.
|
||||
///
|
||||
/// - Parameters:
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
|
||||
/// A property wrapper that tracks changes of a property.
|
||||
///
|
||||
/// This allows values to only publish changes if they have changed since the
|
||||
/// last time they were recieved.
|
||||
@propertyWrapper
|
||||
public struct TrackedChanges<Value> {
|
||||
|
||||
|
||||
/// The current tracking state.
|
||||
private var tracking: TrackingState
|
||||
|
||||
/// The current wrapped value.
|
||||
private var value: Value
|
||||
|
||||
/// Used to check if a new value is equal to an old value.
|
||||
private var isEqual: (Value, Value) -> Bool
|
||||
|
||||
|
||||
/// Access to the underlying property that we are wrapping.
|
||||
public var wrappedValue: Value {
|
||||
get { value }
|
||||
set {
|
||||
@@ -16,7 +25,13 @@ public struct TrackedChanges<Value> {
|
||||
tracking = .needsProcessed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Create a new property that tracks it's changes.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - wrappedValue: The value that we are wrapping.
|
||||
/// - needsProcessed: Whether this value needs processed (default = false).
|
||||
/// - isEqual: Method to compare old values against new values.
|
||||
public init(
|
||||
wrappedValue: Value,
|
||||
needsProcessed: Bool = false,
|
||||
@@ -26,12 +41,18 @@ public struct TrackedChanges<Value> {
|
||||
self.tracking = needsProcessed ? .needsProcessed : .hasProcessed
|
||||
self.isEqual = isEqual
|
||||
}
|
||||
|
||||
|
||||
/// Represents whether a wrapped value has changed and needs processed or not.
|
||||
enum TrackingState {
|
||||
|
||||
/// The state when nothing has changed and we've already processed the current value.
|
||||
case hasProcessed
|
||||
|
||||
/// The state when the value has changed and has not been processed yet.
|
||||
case needsProcessed
|
||||
}
|
||||
|
||||
|
||||
/// Check whether the value needs processed.
|
||||
public var needsProcessed: Bool {
|
||||
get { tracking == .needsProcessed }
|
||||
set {
|
||||
@@ -42,7 +63,7 @@ public struct TrackedChanges<Value> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public var projectedValue: Self {
|
||||
get { self }
|
||||
set { self = newValue }
|
||||
@@ -54,7 +75,12 @@ extension TrackedChanges: Equatable where Value: Equatable {
|
||||
lhs.wrappedValue == rhs.wrappedValue
|
||||
&& lhs.needsProcessed == rhs.needsProcessed
|
||||
}
|
||||
|
||||
|
||||
/// Create a new property that tracks it's changes, using the default equality check.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - wrappedValue: The value that we are wrapping.
|
||||
/// - needsProcessed: Whether this value needs processed (default = false).
|
||||
public init(
|
||||
wrappedValue: Value,
|
||||
needsProcessed: Bool = false
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "xcode build server",
|
||||
"version": "0.2",
|
||||
"bspVersion": "2.0",
|
||||
"languages": [
|
||||
"c",
|
||||
"cpp",
|
||||
"objective-c",
|
||||
"objective-cpp",
|
||||
"swift"
|
||||
],
|
||||
"argv": [
|
||||
"/opt/homebrew/bin/xcode-build-server"
|
||||
],
|
||||
"workspace": "/Volumes/michael/Repos/github.com/hvac-iot/swift-mqtt-dewPoint/.swiftpm/xcode/package.xcworkspace",
|
||||
"build_root": "/Volumes/michael/Repos/github.com",
|
||||
"scheme": "dewPoint-controller-Package",
|
||||
"kind": "xcode"
|
||||
}
|
||||
Reference in New Issue
Block a user