iOS/Sources/Shared/API/Webhook/Sensors/BatterySensor.swift
Bruno Pantaleão Gonçalves 4fa6de6b11
Add Apple Watch battery sensor (#2897)
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->
2024-08-02 11:32:24 +02:00

109 lines
3.7 KiB
Swift

import Foundation
import PromiseKit
final class BatterySensorUpdateSignaler: SensorProviderUpdateSignaler, DeviceWrapperBatteryNotificationObserver {
let signal: () -> Void
init(signal: @escaping () -> Void) {
self.signal = signal
Current.device.batteryNotificationCenter.register(observer: self)
}
func deviceBatteryStateDidChange(_ center: DeviceWrapperBatteryNotificationCenter) {
Current.Log.info("signalling battery status change")
signal()
}
}
public class BatterySensor: SensorProvider {
public let request: SensorProviderRequest
public required init(request: SensorProviderRequest) {
self.request = request
}
public func sensors() -> Promise<[WebhookSensor]> {
// Set up our observer for battery state changes
let _: BatterySensorUpdateSignaler = request.dependencies.updateSignaler(for: self)
return .value(
Current.device.batteries()
.flatMap { Self.sensors(battery: $0) }
)
}
private static func sensors(battery: DeviceBattery) -> [WebhookSensor] {
let icon: String = BatteryIcon.forBatteryLevel(battery.level, state: battery.state)
let isLowPowerMode = Current.device.isLowPowerMode()
let sensorNamePrefix = battery.name ?? "Battery"
let sensorIDPrefix = battery.uniqueID ?? "battery"
let levelSensor = with(WebhookSensor(
name: "\(sensorNamePrefix) Level",
uniqueID: "\(sensorIDPrefix)_level",
icon: icon,
deviceClass: .battery,
state: battery.level
)) {
$0.Attributes = battery.attributes
$0.UnitOfMeasurement = "%"
}
let stateSensor = with(WebhookSensor(
name: "\(sensorNamePrefix) State",
uniqueID: "\(sensorIDPrefix)_state",
icon: icon,
state: battery.state.description
)) {
$0.Attributes = [
"Low Power Mode": isLowPowerMode,
].merging(battery.attributes, uniquingKeysWith: { a, _ in a })
}
return [levelSensor, stateSensor]
}
}
enum BatteryIcon {
static func forBatteryLevel(_ batteryLevel: Int, state: DeviceBattery.State) -> String {
switch state {
case .charging:
return chargingIcon(level: batteryLevel)
case .unplugged:
return unpluggedIcon(level: batteryLevel)
case .full:
return "mdi:battery"
}
}
static func chargingIcon(level: Int) -> String {
switch level {
case 100...: return "mdi:battery-charging-100"
case 90...: return "mdi:battery-charging-80"
case 80...: return "mdi:battery-charging-80"
case 70...: return "mdi:battery-charging-60"
case 60...: return "mdi:battery-charging-60"
case 50...: return "mdi:battery-charging-40"
case 40...: return "mdi:battery-charging-40"
case 30...: return "mdi:battery-charging-20"
case 20...: return "mdi:battery-charging-20"
case 10...: return "mdi:battery-outline"
default: return "mdi:battery-outline"
}
}
static func unpluggedIcon(level: Int) -> String {
switch level {
case 100...: return "mdi:battery"
case 90...: return "mdi:battery-90"
case 80...: return "mdi:battery-80"
case 70...: return "mdi:battery-70"
case 60...: return "mdi:battery-60"
case 50...: return "mdi:battery-50"
case 40...: return "mdi:battery-40"
case 30...: return "mdi:battery-30"
case 20...: return "mdi:battery-20"
case 10...: return "mdi:battery-10"
default: return "mdi:battery-outline"
}
}
}