From d9481e065719b9dd095e95045bbb1bc62e31f56b Mon Sep 17 00:00:00 2001 From: Paul Schmiedmayer Date: Sun, 28 Mar 2021 16:58:39 +0200 Subject: [PATCH] Improve the device discovery and command line tool --- Sources/NIOLIFX/Devices/Device.swift | 13 ++-- .../DevicePropertyTypes/PowerLevel.swift | 6 +- Sources/NIOLIFX/LIFXDeviceManager.swift | 16 ++++- .../NIOLIFX/Messages/PowerLevelMessage.swift | 12 +--- Sources/lifx/main.swift | 60 ++++++++----------- 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/Sources/NIOLIFX/Devices/Device.swift b/Sources/NIOLIFX/Devices/Device.swift index 6468968..43fbdc4 100644 --- a/Sources/NIOLIFX/Devices/Device.swift +++ b/Sources/NIOLIFX/Devices/Device.swift @@ -95,12 +95,17 @@ public class Device { self.address = address self.deviceManager = deviceManager self.service.wrappedValue = service - self.label.load() - self.group.load() - self.location.load() - self.powerLevel.load() } + public func loadBasicInformation() -> EventLoopFuture { + label.load() + .and(group.load()) + .and(location.load()) + .and(powerLevel.load()) + .map { _ in } + } + + /** Set the power level of the `Device`. */ diff --git a/Sources/NIOLIFX/Devices/DevicePropertyTypes/PowerLevel.swift b/Sources/NIOLIFX/Devices/DevicePropertyTypes/PowerLevel.swift index 196c158..5d9c3a9 100644 --- a/Sources/NIOLIFX/Devices/DevicePropertyTypes/PowerLevel.swift +++ b/Sources/NIOLIFX/Devices/DevicePropertyTypes/PowerLevel.swift @@ -58,15 +58,15 @@ extension ByteBuffer { func getPowerLevel(at index: Int) throws -> (powerLevel: Device.PowerLevel, byteSize: Int) { precondition(index >= 0, "index must not be negative") - guard let rawService: Device.PowerLevel.RawValue = getInteger(at: index, endianness: .little) else { + guard let rawPowerLevel: Device.PowerLevel.RawValue = getInteger(at: index, endianness: .little) else { throw ByteBufferError.notEnoughtReadableBytes } - guard let service = Device.PowerLevel(rawValue: rawService) else { + guard let powerLevel = Device.PowerLevel(rawValue: rawPowerLevel) else { throw ByteBufferError.notEnoughtReadableBytes } - return (service, MemoryLayout.size) + return (powerLevel, MemoryLayout.size) } /** diff --git a/Sources/NIOLIFX/LIFXDeviceManager.swift b/Sources/NIOLIFX/LIFXDeviceManager.swift index 177ada5..bcf2aa9 100644 --- a/Sources/NIOLIFX/LIFXDeviceManager.swift +++ b/Sources/NIOLIFX/LIFXDeviceManager.swift @@ -108,7 +108,21 @@ public final class LIFXDeviceManager { let timeoutTask = eventLoop.scheduleTask(in: Constants.lifxTimout) { self.devices.subtracting(newlyDiscoveredDevices).forEach({ self.devices.remove($0) }) - discoverPromise.succeed(()) + + LIFXDeviceManager.logger.info( + "Disovered \(self.devices.count). Loading basic information for all devices." + ) + + EventLoopFuture + .reduce( + Void(), + self.devices.map { device in + device.loadBasicInformation() + }, + on: self.eventLoop, + { _, _ in } + ) + .cascade(to: discoverPromise) } userOutboundEventFuture.whenSuccess { diff --git a/Sources/NIOLIFX/Messages/PowerLevelMessage.swift b/Sources/NIOLIFX/Messages/PowerLevelMessage.swift index 8cef490..1eb9906 100644 --- a/Sources/NIOLIFX/Messages/PowerLevelMessage.swift +++ b/Sources/NIOLIFX/Messages/PowerLevelMessage.swift @@ -59,19 +59,11 @@ class PowerLevelMessage: Message { requestResponse: Bool, sequenceNumber: UInt8, payload: ByteBuffer) throws { - guard payload.readableBytes >= 2 else { + guard payload.readableBytes >= MemoryLayout.size else { throw MessageError.messageFormat } - guard let rawPowerLevel: UInt16 = payload.getInteger(at: payload.readerIndex) else { - throw ByteBufferError.notEnoughtBytes - } - - guard let powerLevel = Device.PowerLevel(rawValue: rawPowerLevel) else { - throw MessageError.messageFormat - } - - self.powerLevel = powerLevel + self.powerLevel = try payload.getPowerLevel(at: payload.readerIndex).powerLevel super.init(source: source, target: target, diff --git a/Sources/lifx/main.swift b/Sources/lifx/main.swift index a0fcd8a..9df486a 100644 --- a/Sources/lifx/main.swift +++ b/Sources/lifx/main.swift @@ -1,4 +1,5 @@ import ArgumentParser +import Foundation import Logging import NIO import NIOLIFX @@ -32,7 +33,7 @@ struct LIFX: ParsableCommand { logger.logLevel = logLevel let networkInterface = getNetworkInterface(logger) - let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 2) + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) let lifxDeviceManager = try LIFXDeviceManager(using: networkInterface, on: eventLoopGroup, logLevel: logLevel) @@ -49,41 +50,32 @@ struct LIFX: ParsableCommand { """ ) - while let _ = readLine(strippingNewline: false) { - print("🔍 ... discovering new devices.") - lifxDeviceManager.discoverDevices() - .whenSuccess { - guard !lifxDeviceManager.devices.isEmpty else { - print("🔍 Could not find any LIFX devices.") - return - } - - print("✅ Discovered the following devices:") - for device in lifxDeviceManager.devices { - print(" 💡 \(device.label) (\(device.group), \(device.location)): \(device.powerLevel.wrappedValue == .enabled ? "On" : "Off")") - } - - print("⚙️ Turning all devices \(on ? "on" : "off")") - lifxDeviceManager.devices.forEach { device in - let future: EventLoopFuture - if on { - future = device.set(powerLevel: .enabled) - } else { - future = device.set(powerLevel: .standby) - } - - future.whenSuccess { powerLevel in - print(" 💡 \(device.label) (\(device.group), \(device.location)) is now turned \(device.powerLevel.wrappedValue == .enabled ? "on" : "off").") - } - future.whenFailure { error in - logger.error("Could not change powerLevel of \(device.label): \"\(error)\"") - } - - on.toggle() - } + print("🔍 ... discovering new devices.") + lifxDeviceManager.discoverDevices() + .whenSuccess { + guard !lifxDeviceManager.devices.isEmpty else { + print("🔍 Could not find any LIFX devices.") + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { + try! eventLoopGroup.syncShutdownGracefully() + LIFX.exit() } + return + } + + print("✅ Discovered the following devices:") + for device in lifxDeviceManager.devices { + print(" 💡 \(device.label) (\(device.group), \(device.location)): \(device.powerLevel.wrappedValue == .enabled ? "On" : "Off")") + } + } + + while let _ = readLine(strippingNewline: false) { + print("⚙️ Turning all devices \(on ? "on" : "off")") + for device in lifxDeviceManager.devices { + _ = try device.set(powerLevel: on ? .enabled : .standby).wait() + on.toggle() + } } - + try eventLoopGroup.syncShutdownGracefully() }