feat: Working on async integrations.
This commit is contained in:
@@ -1 +1,9 @@
|
|||||||
--self init-only
|
--self init-only
|
||||||
|
--indent 2
|
||||||
|
--ifdef indent
|
||||||
|
--trimwhitespace always
|
||||||
|
--wraparguments preserve
|
||||||
|
--wrapcollections preserve
|
||||||
|
--wrapconditions after-first
|
||||||
|
--typeblanklines preserve
|
||||||
|
--commas inline
|
||||||
|
|||||||
6
Dockerfile.test
Normal file
6
Dockerfile.test
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM swift:5.10
|
||||||
|
WORKDIR /app
|
||||||
|
COPY ./Package.* ./
|
||||||
|
RUN swift package resolve
|
||||||
|
COPY . .
|
||||||
|
CMD ["/bin/bash", "-xc", "swift", "test"]
|
||||||
4
Makefile
4
Makefile
@@ -23,6 +23,8 @@ stop-mosquitto:
|
|||||||
@docker-compose rm -f mosquitto || true
|
@docker-compose rm -f mosquitto || true
|
||||||
|
|
||||||
test-docker:
|
test-docker:
|
||||||
@docker-compose run -i test
|
@docker-compose run --remove-orphans -i --rm test
|
||||||
@docker-compose kill mosquitto-test
|
@docker-compose kill mosquitto-test
|
||||||
@docker-compose rm -f
|
@docker-compose rm -f
|
||||||
|
|
||||||
|
test: test-docker
|
||||||
|
|||||||
@@ -1,65 +1,117 @@
|
|||||||
import Psychrometrics
|
import Psychrometrics
|
||||||
|
|
||||||
|
/// Represents a temperature and humidity sensor that can be used to derive
|
||||||
|
/// the dew-point temperature and enthalpy values.
|
||||||
|
///
|
||||||
public struct TemperatureAndHumiditySensor: Equatable, Identifiable {
|
public struct TemperatureAndHumiditySensor: Equatable, Identifiable {
|
||||||
/// The identifier of the sensor, same as the location.
|
|
||||||
public var id: Location { location }
|
|
||||||
|
|
||||||
public let altitude: Length
|
/// The identifier of the sensor, same as the location.
|
||||||
|
public var id: Location { location }
|
||||||
|
|
||||||
/// The location identifier of the sensor
|
/// The altitude of the sensor.
|
||||||
public let location: Location
|
public let altitude: Length
|
||||||
|
|
||||||
/// The current temperature value of the sensor.
|
/// The current humidity value of the sensor.
|
||||||
@TrackedChanges
|
@TrackedChanges
|
||||||
public var temperature: Temperature?
|
public var humidity: RelativeHumidity?
|
||||||
|
|
||||||
/// The current humidity value of the sensor.
|
/// The location identifier of the sensor
|
||||||
@TrackedChanges
|
public let location: Location
|
||||||
public var humidity: RelativeHumidity?
|
|
||||||
|
|
||||||
/// The psychrometric units of the sensor.
|
/// The current temperature value of the sensor.
|
||||||
public let units: PsychrometricEnvironment.Units
|
@TrackedChanges
|
||||||
|
public var temperature: Temperature?
|
||||||
|
|
||||||
|
/// The topics to listen for updated sensor values.
|
||||||
|
public let topics: Topics
|
||||||
|
|
||||||
|
/// The psychrometric units of the sensor.
|
||||||
|
public let units: PsychrometricEnvironment.Units
|
||||||
|
|
||||||
|
/// Create a new temperature and humidity sensor.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - location: The location of the sensor.
|
||||||
|
/// - altitude: The altitude of the sensor.
|
||||||
|
/// - temperature: The current temperature value of the sensor.
|
||||||
|
/// - humidity: The current relative humidity value of the sensor.
|
||||||
|
/// - needsProcessed: If the sensor needs to be processed.
|
||||||
|
/// - units: The unit of measure for the sensor.
|
||||||
|
public init(
|
||||||
|
location: Location,
|
||||||
|
altitude: Length = .feet(800.0),
|
||||||
|
temperature: Temperature? = nil,
|
||||||
|
humidity: RelativeHumidity? = nil,
|
||||||
|
needsProcessed: Bool = false,
|
||||||
|
units: PsychrometricEnvironment.Units = .imperial,
|
||||||
|
topics: Topics? = nil
|
||||||
|
) {
|
||||||
|
self.altitude = altitude
|
||||||
|
self.location = location
|
||||||
|
self._temperature = TrackedChanges(wrappedValue: temperature, needsProcessed: needsProcessed)
|
||||||
|
self._humidity = TrackedChanges(wrappedValue: humidity, needsProcessed: needsProcessed)
|
||||||
|
self.units = units
|
||||||
|
self.topics = topics ?? .init(location: location)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The calculated enthalpy of the sensor.
|
||||||
|
public var enthalpy: EnthalpyOf<MoistAir>? {
|
||||||
|
guard let temperature = temperature,
|
||||||
|
let humidity = humidity,
|
||||||
|
!temperature.rawValue.isNaN,
|
||||||
|
!humidity.rawValue.isNaN
|
||||||
|
else { return nil }
|
||||||
|
return .init(dryBulb: temperature, humidity: humidity, altitude: altitude, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the MQTT topics to listen for updated sensor values on.
|
||||||
|
public struct Topics: Equatable {
|
||||||
|
|
||||||
|
/// The temperature topic of the sensor.
|
||||||
|
public let temperature: String
|
||||||
|
|
||||||
|
/// The humidity topic of the sensor.
|
||||||
|
public let humidity: String
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
location: Location,
|
temperature: String,
|
||||||
altitude: Length = .feet(800.0),
|
humidity: String
|
||||||
temperature: Temperature? = nil,
|
|
||||||
humidity: RelativeHumidity? = nil,
|
|
||||||
needsProcessed: Bool = false,
|
|
||||||
units: PsychrometricEnvironment.Units = .imperial
|
|
||||||
) {
|
) {
|
||||||
self.altitude = altitude
|
self.temperature = temperature
|
||||||
self.location = location
|
self.humidity = humidity
|
||||||
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.
|
init(location: TemperatureAndHumiditySensor.Location) {
|
||||||
public var dewPoint: DewPoint? {
|
self.temperature = "sensors/\(location.rawValue)/temperature"
|
||||||
guard let temperature = temperature,
|
self.humidity = "sensors/\(location.rawValue)/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,7 +1,5 @@
|
|||||||
|
|
||||||
/// A container for all the different MQTT 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 {
|
public struct Topics: Codable, Equatable {
|
||||||
|
|
||||||
/// The command topics the application can publish to.
|
/// The command topics the application can publish to.
|
||||||
public var commands: Commands
|
public var commands: Commands
|
||||||
|
|
||||||
@@ -35,7 +33,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// Represents the sensor topics.
|
/// Represents the sensor topics.
|
||||||
public struct Sensors: Codable, Equatable {
|
public struct Sensors: Codable, Equatable {
|
||||||
|
|
||||||
public var mixedAirSensor: TemperatureAndHumiditySensor<State.Sensors.MixedAir>
|
public var mixedAirSensor: TemperatureAndHumiditySensor<State.Sensors.MixedAir>
|
||||||
public var postCoilSensor: TemperatureAndHumiditySensor<State.Sensors.PostCoil>
|
public var postCoilSensor: TemperatureAndHumiditySensor<State.Sensors.PostCoil>
|
||||||
public var returnAirSensor: TemperatureAndHumiditySensor<State.Sensors.Return>
|
public var returnAirSensor: TemperatureAndHumiditySensor<State.Sensors.Return>
|
||||||
@@ -81,7 +78,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// A container for set point related topics used by the application.
|
/// A container for set point related topics used by the application.
|
||||||
public struct SetPoints: Codable, Equatable {
|
public struct SetPoints: Codable, Equatable {
|
||||||
|
|
||||||
/// The topic for the humidify set point.
|
/// The topic for the humidify set point.
|
||||||
public var humidify: Humidify
|
public var humidify: Humidify
|
||||||
|
|
||||||
@@ -103,7 +99,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// A container for the humidification set point topics used by the application.
|
/// A container for the humidification set point topics used by the application.
|
||||||
public struct Humidify: Codable, Equatable {
|
public struct Humidify: Codable, Equatable {
|
||||||
|
|
||||||
/// The topic for dew point control mode set point.
|
/// The topic for dew point control mode set point.
|
||||||
public var dewPoint: String
|
public var dewPoint: String
|
||||||
|
|
||||||
@@ -126,7 +121,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// A container for dehumidifcation set point topics.
|
/// A container for dehumidifcation set point topics.
|
||||||
public struct Dehumidify: Codable, Equatable {
|
public struct Dehumidify: Codable, Equatable {
|
||||||
|
|
||||||
/// A low setting for dew point control modes.
|
/// A low setting for dew point control modes.
|
||||||
public var lowDewPoint: String
|
public var lowDewPoint: String
|
||||||
|
|
||||||
@@ -162,7 +156,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// A container for control state topics used by the application.
|
/// A container for control state topics used by the application.
|
||||||
public struct States: Codable, Equatable {
|
public struct States: Codable, Equatable {
|
||||||
|
|
||||||
/// The topic for the control mode.
|
/// The topic for the control mode.
|
||||||
public var mode: String
|
public var mode: String
|
||||||
|
|
||||||
@@ -183,7 +176,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// A container for reading the current state of a relay.
|
/// A container for reading the current state of a relay.
|
||||||
public struct Relays: Codable, Equatable {
|
public struct Relays: Codable, Equatable {
|
||||||
|
|
||||||
/// The dehumidification stage-1 relay topic.
|
/// The dehumidification stage-1 relay topic.
|
||||||
public var dehumdification1: String
|
public var dehumdification1: String
|
||||||
|
|
||||||
@@ -213,7 +205,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// A container for commands topics that the application can publish to.
|
/// A container for commands topics that the application can publish to.
|
||||||
public struct Commands: Codable, Equatable {
|
public struct Commands: Codable, Equatable {
|
||||||
|
|
||||||
/// The relay command topics.
|
/// The relay command topics.
|
||||||
public var relays: Relays
|
public var relays: Relays
|
||||||
|
|
||||||
@@ -227,7 +218,6 @@ public struct Topics: Codable, Equatable {
|
|||||||
|
|
||||||
/// A container for relay command topics used by the application.
|
/// A container for relay command topics used by the application.
|
||||||
public struct Relays: Codable, Equatable {
|
public struct Relays: Codable, Equatable {
|
||||||
|
|
||||||
/// The dehumidification stage-1 relay topic.
|
/// The dehumidification stage-1 relay topic.
|
||||||
public var dehumidification1: String
|
public var dehumidification1: String
|
||||||
|
|
||||||
@@ -257,8 +247,9 @@ public struct Topics: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Helpers
|
// MARK: Helpers
|
||||||
extension Topics.Sensors.TemperatureAndHumiditySensor {
|
|
||||||
public static func `default`(location: String) -> Self {
|
public extension Topics.Sensors.TemperatureAndHumiditySensor {
|
||||||
|
static func `default`(location: String) -> Self {
|
||||||
.init(
|
.init(
|
||||||
temperature: "sensors/\(location)/temperature",
|
temperature: "sensors/\(location)/temperature",
|
||||||
humidity: "sensors/\(location)/humidity",
|
humidity: "sensors/\(location)/humidity",
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import XCTest
|
@testable import ClientLive
|
||||||
import EnvVars
|
import EnvVars
|
||||||
import Logging
|
import Logging
|
||||||
import Models
|
import Models
|
||||||
@testable import ClientLive
|
import MQTTNIO
|
||||||
|
import NIO
|
||||||
import Psychrometrics
|
import Psychrometrics
|
||||||
|
import XCTest
|
||||||
|
|
||||||
final class AsyncClientTests: XCTestCase {
|
final class AsyncClientTests: XCTestCase {
|
||||||
|
|
||||||
@@ -16,7 +18,7 @@ final class AsyncClientTests: XCTestCase {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
func createClient(identifier: String) -> AsyncClient {
|
func createClient(identifier: String) -> AsyncClient {
|
||||||
let envVars = EnvVars.init(
|
let envVars = EnvVars(
|
||||||
appEnv: .testing,
|
appEnv: .testing,
|
||||||
host: Self.hostname,
|
host: Self.hostname,
|
||||||
port: "1883",
|
port: "1883",
|
||||||
@@ -42,4 +44,73 @@ final class AsyncClientTests: XCTestCase {
|
|||||||
try await client.publishSensor(.mixed(.init(temperature: 72.123, humidity: 50.5, needsProcessed: true)))
|
try await client.publishSensor(.mixed(.init(temperature: 72.123, humidity: 50.5, needsProcessed: true)))
|
||||||
await client.shutdown()
|
await client.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testNewSensorSyntax() async throws {
|
||||||
|
let client = createClient(identifier: "testNewSensorSyntax")
|
||||||
|
let mqtt = client.client
|
||||||
|
let receivedPublishInfo = PublishInfoContainer()
|
||||||
|
let payload = ByteBufferAllocator().buffer(string: "75.123")
|
||||||
|
let sensor = TemperatureAndHumiditySensor(location: .return)
|
||||||
|
|
||||||
|
await client.connect()
|
||||||
|
|
||||||
|
try await mqtt.subscribeToTemperature(sensor: sensor)
|
||||||
|
|
||||||
|
let listener = mqtt.createPublishListener()
|
||||||
|
|
||||||
|
Task { [receivedPublishInfo] in
|
||||||
|
for await result in listener {
|
||||||
|
switch result {
|
||||||
|
case let .failure(error):
|
||||||
|
XCTFail("\(error)")
|
||||||
|
case let .success(publish):
|
||||||
|
await receivedPublishInfo.addPublishInfo(publish)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try await mqtt.publish(to: sensor.topics.temperature, payload: payload, qos: .atLeastOnce)
|
||||||
|
|
||||||
|
try await Task.sleep(for: .seconds(2))
|
||||||
|
|
||||||
|
XCTAssertEqual(receivedPublishInfo.count, 1)
|
||||||
|
|
||||||
|
if let publish = receivedPublishInfo.first {
|
||||||
|
var buffer = publish.payload
|
||||||
|
let string = buffer.readString(length: buffer.readableBytes)
|
||||||
|
XCTAssertEqual(string, "75.123")
|
||||||
|
} else {
|
||||||
|
XCTFail("Did not receive any publish info.")
|
||||||
|
}
|
||||||
|
|
||||||
|
try await mqtt.disconnect()
|
||||||
|
try mqtt.syncShutdownGracefully()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Helpers for tests, some of these should be able to be removed once the AsyncClient interface is done.
|
||||||
|
|
||||||
|
extension MQTTClient {
|
||||||
|
|
||||||
|
func subscribeToTemperature(sensor: TemperatureAndHumiditySensor) async throws {
|
||||||
|
_ = try await subscribe(to: [
|
||||||
|
.init(topicFilter: sensor.topics.temperature, qos: .atLeastOnce)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PublishInfoContainer {
|
||||||
|
private var receivedPublishInfo: [MQTTPublishInfo]
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.receivedPublishInfo = []
|
||||||
|
}
|
||||||
|
|
||||||
|
func addPublishInfo(_ info: MQTTPublishInfo) async {
|
||||||
|
receivedPublishInfo.append(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
var count: Int { receivedPublishInfo.count }
|
||||||
|
|
||||||
|
var first: MQTTPublishInfo? { receivedPublishInfo.first }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,18 +30,18 @@ final class ClientLiveTests: XCTestCase {
|
|||||||
let payloadString = "test"
|
let payloadString = "test"
|
||||||
let payload = ByteBufferAllocator().buffer(string: payloadString)
|
let payload = ByteBufferAllocator().buffer(string: payloadString)
|
||||||
|
|
||||||
let client = self.createMQTTClient(identifier: "testMQTTListener_publisher")
|
let client = createMQTTClient(identifier: "testMQTTListener_publisher")
|
||||||
_ = try client.connect().wait()
|
_ = try client.connect().wait()
|
||||||
client.addPublishListener(named: "test") { result in
|
client.addPublishListener(named: "test") { result in
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let publish):
|
case let .success(publish):
|
||||||
var buffer = publish.payload
|
var buffer = publish.payload
|
||||||
let string = buffer.readString(length: buffer.readableBytes)
|
let string = buffer.readString(length: buffer.readableBytes)
|
||||||
XCTAssertEqual(string, payloadString)
|
XCTAssertEqual(string, payloadString)
|
||||||
lock.withLock {
|
lock.withLock {
|
||||||
publishRecieved.append(publish)
|
publishRecieved.append(publish)
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case let .failure(error):
|
||||||
XCTFail("\(error)")
|
XCTFail("\(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,6 @@ final class ClientLiveTests: XCTestCase {
|
|||||||
|
|
||||||
try client.disconnect().wait()
|
try client.disconnect().wait()
|
||||||
try client.syncShutdownGracefully()
|
try client.syncShutdownGracefully()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func test_client2_returnTemperature_listener() throws {
|
func test_client2_returnTemperature_listener() throws {
|
||||||
@@ -146,15 +145,16 @@ final class ClientLiveTests: XCTestCase {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// MARK: - Helpers
|
// MARK: - Helpers
|
||||||
|
|
||||||
func createMQTTClient(identifier: String) -> MQTTNIO.MQTTClient {
|
func createMQTTClient(identifier: String) -> MQTTNIO.MQTTClient {
|
||||||
MQTTNIO.MQTTClient(
|
MQTTNIO.MQTTClient(
|
||||||
host: Self.hostname,
|
host: Self.hostname,
|
||||||
port: 1883,
|
port: 1883,
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
eventLoopGroupProvider: .shared(eventLoopGroup),
|
eventLoopGroupProvider: .shared(eventLoopGroup),
|
||||||
logger: self.logger,
|
logger: logger,
|
||||||
configuration: .init(version: .v5_0)
|
configuration: .init(version: .v5_0)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func createWebSocketClient(identifier: String) -> MQTTNIO.MQTTClient {
|
// func createWebSocketClient(identifier: String) -> MQTTNIO.MQTTClient {
|
||||||
@@ -177,10 +177,10 @@ final class ClientLiveTests: XCTestCase {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
let logger: Logger = {
|
let logger: Logger = {
|
||||||
var logger = Logger(label: "MQTTTests")
|
var logger = Logger(label: "MQTTTests")
|
||||||
logger.logLevel = .trace
|
logger.logLevel = .trace
|
||||||
return logger
|
return logger
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let eventLoopGroup = MultiThreadedEventLoopGroup.init(numberOfThreads: 1)
|
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ services:
|
|||||||
env_file: .env
|
env_file: .env
|
||||||
|
|
||||||
test:
|
test:
|
||||||
image: swift:5.10
|
build:
|
||||||
#build:
|
context: .
|
||||||
#context: ./
|
dockerfile: Dockerfile.test
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
networks:
|
networks:
|
||||||
- test
|
- test
|
||||||
volumes:
|
# volumes:
|
||||||
- .:/app
|
# - .:/app
|
||||||
depends_on:
|
depends_on:
|
||||||
- mosquitto-test
|
- mosquitto-test
|
||||||
environment:
|
environment:
|
||||||
@@ -44,4 +44,3 @@ networks:
|
|||||||
test:
|
test:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
external: false
|
external: false
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user