Added ability to load topics from a configuration file in the root directory. Dew point calculation seems to be off though.

This commit is contained in:
2021-10-17 18:24:36 -04:00
parent 3f78a53014
commit d8734913e0
8 changed files with 255 additions and 84 deletions

View File

@@ -20,6 +20,7 @@ public func bootstrap(
logger?.debug("Bootstrapping Dew Point Controller...")
return loadEnvVars(eventLoopGroup: eventLoopGroup, logger: logger)
.and(loadTopics(eventLoopGroup: eventLoopGroup, logger: logger))
.makeDewPointEnvironment(eventLoopGroup: eventLoopGroup, logger: logger)
.connectToMQTTBroker(logger: logger)
}
@@ -68,7 +69,42 @@ private func loadEnvVars(eventLoopGroup: EventLoopGroup, logger: Logger?) -> Eve
return eventLoopGroup.next().makeSucceededFuture(envVars)
}
extension EventLoopFuture where Value == EnvVars {
func loadTopics(eventLoopGroup: EventLoopGroup, logger: Logger?) -> EventLoopFuture<Topics> {
logger?.debug("Loading topics from file...")
let topicsFilePath = URL(fileURLWithPath: #file)
.deletingLastPathComponent()
.deletingLastPathComponent()
.deletingLastPathComponent()
.appendingPathComponent(".topics")
let decoder = JSONDecoder()
let data = try? Data.init(contentsOf: topicsFilePath)
logger?.debug("Data: \(data!)")
let localTopics = data
.flatMap { try? decoder.decode(Topics.self, from: $0) }
// .flatMap { try decoder.decode(Topics.self, from: $0) }
logger?.debug(
localTopics == nil
? "Failed to load topics from file, falling back to defaults."
: "Done loading topics from file."
)
// let defaultData = Topics()
// let jsonData = try! JSONEncoder().encode(defaultData)
// let string = String.init(data: jsonData, encoding: .utf8) ?? "Invalid data"
// logger?.debug("\(string)")
// try! string.write(to: topicsFilePath, atomically: true, encoding: .utf8)
//
return eventLoopGroup.next().makeSucceededFuture(localTopics ?? .init())
}
extension EventLoopFuture where Value == (EnvVars, Topics) {
/// Creates the ``DewPointEnvironment`` for the application after the ``EnvVars`` have been loaded.
///
@@ -79,13 +115,13 @@ extension EventLoopFuture where Value == EnvVars {
eventLoopGroup: EventLoopGroup,
logger: Logger?
) -> EventLoopFuture<DewPointEnvironment> {
map { envVars in
map { envVars, topics in
let nioClient = MQTTClient(envVars: envVars, eventLoopGroup: eventLoopGroup, logger: logger)
return DewPointEnvironment.init(
mqttClient: .live(client: nioClient),
envVars: envVars,
nioClient: nioClient,
topics: .init(envVars: envVars)
topics: topics
)
}
}
@@ -128,22 +164,3 @@ extension MQTTClient {
)
}
}
// MARK: - TODO Make topics loadable from a file in the root directory.
extension Topics {
init(envVars: EnvVars) {
self.init(
sensors: .init(
temperature: envVars.temperatureSensor,
humidity: envVars.humiditySensor,
dewPoint: envVars.dewPointTopic
),
relays: .init(
dehumidification1: envVars.dehumidificationStage1Relay,
dehumidification2: envVars.dehumidificationStage2Relay,
humidification: envVars.humidificationRelay
)
)
}
}

View File

@@ -24,15 +24,6 @@ public struct EnvVars: Codable, Equatable {
/// The MQTT user password.
public var password: String?
// MARK: TODO Move Topics to their own file that can be loaded.
// Topics
public var dehumidificationStage1Relay: String
public var dehumidificationStage2Relay: String
public var dewPointTopic: String
public var humidificationRelay: String
public var humiditySensor: String
public var temperatureSensor: String
/// Create a new ``EnvVars``
///
/// - Parameters:
@@ -48,13 +39,7 @@ public struct EnvVars: Codable, Equatable {
port: String? = "1883",
identifier: String = "dewPoint-controller",
userName: String? = "mqtt_user",
password: String? = "secret!",
dehumidificationStage1Relay: String = "relays/dehumidification_1",
dehumidificationStage2Relay: String = "relays/dehumidification_2",
dewPointTopic: String = "sensors/dew_point",
humidificationRelay: String = "relays/humidification",
humiditySensor: String = "sensors/humidity",
temperatureSensor: String = "sensors/temperature"
password: String? = "secret!"
){
self.appEnv = appEnv
self.host = host
@@ -62,12 +47,6 @@ public struct EnvVars: Codable, Equatable {
self.identifier = identifier
self.userName = userName
self.password = password
self.dehumidificationStage1Relay = dehumidificationStage1Relay
self.dehumidificationStage2Relay = dehumidificationStage2Relay
self.dewPointTopic = dewPointTopic
self.humidificationRelay = humidificationRelay
self.humiditySensor = humiditySensor
self.temperatureSensor = temperatureSensor
}
/// Custom coding keys.
@@ -78,12 +57,6 @@ public struct EnvVars: Codable, Equatable {
case identifier = "MQTT_IDENTIFIER"
case userName = "MQTT_USERNAME"
case password = "MQTT_PASSWORD"
case dehumidificationStage1Relay = "DEHUMIDIFICATION_STAGE_1_RELAY"
case dehumidificationStage2Relay = "DEHUMIDIFICATION_STAGE_2_RELAY"
case dewPointTopic = "DEW_POINT_TOPIC"
case humidificationRelay = "HUMIDIFICATION_RELAY"
case humiditySensor = "HUMIDITY_SENSOR"
case temperatureSensor = "TEMPERATURE_SENSOR"
}
/// Represents the different app environments.

View File

@@ -1,27 +1,56 @@
public struct Topics {
/// A container for all the different 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 sensor values from.
public var sensors: Sensors
public var setPoints: SetPoints
public var states: States
public var relays: Relays
/// 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:
/// - sensors: The sensor topics.
/// - setPoints: The set point topics
/// - states: The states topics
/// - relays: The relay topics
public init(
commands: Commands = .init(),
sensors: Sensors = .init(),
setPoints: SetPoints = .init(),
states: States = .init(),
relays: Relays = .init()
states: States = .init()
) {
self.commands = commands
self.sensors = sensors
self.setPoints = setPoints
self.states = states
self.relays = relays
}
public struct Sensors {
/// Represents the sensor topics.
public struct Sensors: Codable, Equatable {
/// The temperature sensor topic.
public var temperature: String
/// The humidity sensor topic.
public var humidity: String
/// The dew point topic (we write / publish this data from the application).
public var dewPoint: String
/// Create a new sensor topic container.
///
/// - Parameters:
/// - temperature: The temperature sensor topic.
/// - humidity: The humidity sensor topic.
/// - dewPoint: The dew point sensor topic.
public init(
temperature: String = "sensors/temperature",
humidity: String = "sensors/humidity",
@@ -33,24 +62,73 @@ public struct Topics {
}
}
public struct SetPoints {
public var humidify: String
/// 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:
/// - humidify: The topic for humidification set points.
/// - dehumidify: The topics for dehumidification set points.
public init(
humidify: String = "set_points/humidify",
humidify: Humidify = .init(),
dehumidify: Dehumidify = .init()
) {
self.humidify = humidify
self.dehumidify = dehumidify
}
public struct 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:
/// - dewPoint: The topic for dew point control mode set point.
/// - relativeHumidity: The topic for relative humidity control mode set point.
public init(
dewPoint: String = "set_points/humidify/dew_point",
relativeHumidity: String = "set_points/humidify/relative_humidity"
) {
self.dewPoint = dewPoint
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:
/// - lowDewPoint: A low setting for dew point control modes.
/// - highDewPoint: A high setting for dew point control modes.
/// - lowRelativeHumidity: A low setting for relative humidity control modes.
/// - highRelativeHumidity: A high setting for relative humidity control modes.
public init(
lowDewPoint: String = "set_points/dehumidify/low_dew_point",
highDewPoint: String = "set_points/dehumidify/high_dew_point",
@@ -65,27 +143,98 @@ public struct Topics {
}
}
public struct States {
/// 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
public init(mode: String = "states/mode") {
/// The relay state topics.
public var relays: Relays
/// Create a new container for control state topics.
///
/// - Parameters:
/// - mode: The topic for the control mode.
public init(
mode: String = "states/mode",
relays: Relays = .init()
) {
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:
/// - dehumidification1: The dehumidification stage-1 relay topic.
/// - dehumidification2: The dehumidification stage-2 relay topic.
/// - humidification: The humidification relay topic.
public init(
dehumidefication1: String = "states/relays/dehumidification_1",
dehumidification2: String = "states/relays/dehumidification_2",
humidification: String = "states/relays/humidification"
) {
self.dehumdification1 = dehumidefication1
self.dehumidification2 = dehumidification2
self.humdification = humidification
}
}
}
public struct Relays {
public var dehumidification1: String
public var dehumidification2: String
public var humidification: String
/// A container for commands topics that the application can publish to.
public struct Commands: Codable, Equatable {
public init(
dehumidification1: String = "relays/dehumidification_1",
dehumidification2: String = "relays/dehumidification_2",
humidification: String = "relays/humidification"
) {
self.dehumidification1 = dehumidification1
self.dehumidification2 = dehumidification2
self.humidification = humidification
/// The relay command topics.
public var relays: Relays
/// Create a new command topics container.
///
/// - Parameters:
/// - relays: The relay command topics.
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:
/// - dehumidification1: The dehumidification stage-1 relay topic.
/// - dehumidification2: The dehumidification stage-2 relay topic.
/// - humidification: The humidification relay topic.
public init(
dehumidification1: String = "relays/dehumidification_1",
dehumidification2: String = "relays/dehumidification_2",
humidification: String = "relays/humidification"
) {
self.dehumidification1 = dehumidification1
self.dehumidification2 = dehumidification2
self.humidification = humidification
}
}
}
}

View File

@@ -22,7 +22,7 @@ if environment.envVars.appEnv == .production {
logger.logLevel = .info
}
let relay = Relay(topic: environment.topics.relays.dehumidification1)
let relay = Relay(topic: environment.topics.commands.relays.dehumidification1)
let tempSensor = Sensor<Temperature>(topic: environment.topics.sensors.temperature)
let humiditySensor = Sensor<RelativeHumidity>(topic: environment.topics.sensors.humidity)