iOS/Sources/Shared/API/Models/WebhookSensor.swift
Zac West 86b0b0a409
Allow disabling individual sensors (#1484)
Fixes #358.

## Summary
Allows toggling on or off certain sensors. This does not currently delete the sensor but instead sets its state to 'unavailable'.

## Screenshots
### App
![Image](https://user-images.githubusercontent.com/74188/107861269-bd96e800-6df9-11eb-93c4-682eab17b157.png)
![Image 2](https://user-images.githubusercontent.com/74188/107861298-d8695c80-6df9-11eb-9496-dc89cdc892c0.png)

### Frontend
<img width="334" alt="entities" src="https://user-images.githubusercontent.com/74188/107861381-5c234900-6dfa-11eb-86c5-27b7f6ea2c2e.png">

## 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
- Sensors are still only showing up in the sensor list if they have been generated during the app lifecycle. So for example the Geocode sensor doesn't show up unless a location update happened, and motion sensors do not show up if motion permission is disabled.
- Avoids removing items from the cache when they aren't around anymore, or when we think they are stale.
2021-02-13 16:55:16 -08:00

176 lines
4.7 KiB
Swift

import Foundation
import ObjectMapper
public struct WebhookSensorSetting {
public enum SettingType {
case `switch`(getter: () -> Bool, setter: (Bool) -> Void)
case stepper(
getter: () -> Double,
setter: (Double) -> Void,
minimum: Double = 0,
maximum: Double = 100,
step: Double = 1,
displayValueFor: ((Double?) -> String?)?
)
}
public let type: SettingType
public let title: String
}
public class WebhookSensor: Mappable, Equatable, Comparable {
public var Attributes: [String: Any]?
public var DeviceClass: DeviceClass?
public var Icon: String?
public var Name: String?
public var State: Any? = "Initial"
public var `Type`: String = "sensor"
public var UniqueID: String?
public var UnitOfMeasurement: String?
public var Settings: [WebhookSensorSetting] = []
init() {}
public required init?(map: Map) {}
convenience init(redacting sensor: WebhookSensor) {
self.init()
self.Name = sensor.Name
self.UniqueID = sensor.UniqueID
self.State = "unavailable"
self.Icon = "mdi:dots-square"
}
convenience init(name: String, uniqueID: String) {
self.init()
self.Name = name
self.UniqueID = uniqueID
}
convenience init(name: String, uniqueID: String, state: Any, unit: String? = nil) {
self.init(name: name, uniqueID: uniqueID)
self.State = state
self.UnitOfMeasurement = unit
}
convenience init(name: String, uniqueID: String, icon: String?, state: Any, unit: String? = nil) {
self.init(name: name, uniqueID: uniqueID, state: state, unit: unit)
self.Icon = icon
}
convenience init(name: String, uniqueID: String, icon: MaterialDesignIcons, state: Any, unit: String? = nil) {
self.init(name: name, uniqueID: uniqueID, icon: "mdi:\(icon.name)", state: state, unit: unit)
}
convenience init(
name: String,
uniqueID: String,
icon: String,
deviceClass: DeviceClass,
state: Any,
unit: String? = nil
) {
self.init(name: name, uniqueID: uniqueID, icon: icon, state: state, unit: unit)
self.DeviceClass = deviceClass
}
// Mappable
public func mapping(map: Map) {
Attributes <- map["attributes"]
Icon <- map["icon"]
State <- map["state"]
`Type` <- map["type"]
UniqueID <- map["unique_id"]
let isUpdate = (map.context as? WebhookSensorContext)?.SensorUpdate ?? false
if !isUpdate {
DeviceClass <- map["device_class"]
Name <- map["name"]
UnitOfMeasurement <- map["unit_of_measurement"]
}
}
public var StateDescription: String? {
if let value = State {
return String(describing: value) + (UnitOfMeasurement.flatMap { " " + $0 } ?? "")
} else {
return nil
}
}
public static func == (lhs: WebhookSensor, rhs: WebhookSensor) -> Bool {
let mapper = Mapper<WebhookSensor>()
let lhsData = try? JSONSerialization.data(withJSONObject: mapper.toJSON(lhs), options: [.sortedKeys])
let rhsData = try? JSONSerialization.data(withJSONObject: mapper.toJSON(rhs), options: [.sortedKeys])
return lhsData == rhsData
}
public static func < (lhs: WebhookSensor, rhs: WebhookSensor) -> Bool {
(lhs.Name ?? "").localizedCompare(rhs.Name ?? "") == .orderedAscending
}
}
public enum DeviceClass: String, CaseIterable {
case battery
case cold
case connectivity
case door
case garage_door
case gas
case heat
case humidity
case illuminance
case light
case lock
case moisture
case motion
case moving
case occupancy
case opening
case plug
case power
case presence
case pressure
case problem
case safety
case smoke
case sound
case temperature
case timestamp
case vibration
case window
}
public class WebhookSensorContext: MapContext {
public var SensorUpdate: Bool = false
convenience init(update: Bool = false) {
self.init()
self.SensorUpdate = update
}
}
public class WebhookSensorResponse: Mappable {
public var Success: Bool = false
public var ErrorMessage: String?
public var ErrorCode: String?
init() {}
init(success: Bool, errorMessage: String? = nil, errorCode: String? = nil) {
self.Success = success
self.ErrorMessage = errorMessage
self.ErrorCode = errorCode
}
public required init?(map: Map) {}
// Mappable
public func mapping(map: Map) {
Success <- map["success"]
ErrorMessage <- map["error.message"]
ErrorCode <- map["error.code"]
}
}