2023-06-03 08:15:00 +02:00
|
|
|
import Foundation
|
|
|
|
|
2023-06-05 13:05:57 +02:00
|
|
|
struct TemperatureMeasurement: Identifiable {
|
2023-06-03 08:15:00 +02:00
|
|
|
|
|
|
|
var sensor0: TemperatureValue
|
|
|
|
|
|
|
|
var sensor1: TemperatureValue
|
2023-06-11 21:57:07 +02:00
|
|
|
|
|
|
|
/// The seconds since 1970
|
2023-06-08 09:52:20 +02:00
|
|
|
var id: Int
|
2023-06-05 13:05:57 +02:00
|
|
|
|
2023-06-08 09:52:20 +02:00
|
|
|
var date: Date {
|
|
|
|
get {
|
|
|
|
Date(seconds: id)
|
|
|
|
}
|
|
|
|
set {
|
|
|
|
id = newValue.seconds
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var secondsToNow: Int {
|
2023-06-11 21:57:07 +02:00
|
|
|
id - Date().seconds
|
2023-06-08 09:52:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var maximumValue: Double? {
|
|
|
|
guard let s0 = sensor0.optionalValue else {
|
|
|
|
return sensor1.optionalValue
|
|
|
|
}
|
|
|
|
guard let s1 = sensor1.optionalValue else {
|
2023-06-14 17:52:43 +02:00
|
|
|
return s0
|
2023-06-08 09:52:20 +02:00
|
|
|
}
|
|
|
|
return max(s0, s1)
|
|
|
|
}
|
|
|
|
|
|
|
|
var minimumValue: Double? {
|
|
|
|
guard let s0 = sensor0.optionalValue else {
|
|
|
|
return sensor1.optionalValue
|
|
|
|
}
|
|
|
|
guard let s1 = sensor1.optionalValue else {
|
2023-06-14 17:52:43 +02:00
|
|
|
return s0
|
2023-06-08 09:52:20 +02:00
|
|
|
}
|
|
|
|
return min(s0, s1)
|
2023-06-05 13:05:57 +02:00
|
|
|
}
|
2023-06-14 17:52:43 +02:00
|
|
|
|
|
|
|
var averageValue: Double? {
|
|
|
|
guard let s0 = sensor0.optionalValue else {
|
|
|
|
return sensor1.optionalValue
|
|
|
|
}
|
|
|
|
guard let s1 = sensor1.optionalValue else {
|
|
|
|
return s0
|
|
|
|
}
|
|
|
|
return (s0 + s1) / 2
|
|
|
|
}
|
|
|
|
|
|
|
|
var displayText: String {
|
|
|
|
guard let averageValue else {
|
|
|
|
return "-"
|
|
|
|
}
|
|
|
|
return String(format: "%.1f °C", averageValue)
|
|
|
|
}
|
2023-06-08 09:52:20 +02:00
|
|
|
}
|
2023-06-05 13:05:57 +02:00
|
|
|
|
2023-06-08 09:52:20 +02:00
|
|
|
extension TemperatureMeasurement {
|
|
|
|
|
|
|
|
init(sensor0: TemperatureValue, sensor1: TemperatureValue, date: Date) {
|
|
|
|
self.sensor0 = sensor0
|
|
|
|
self.sensor1 = sensor1
|
|
|
|
self.id = date.seconds
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension TemperatureMeasurement: Codable {
|
|
|
|
|
|
|
|
init(from decoder: Decoder) throws {
|
|
|
|
var container = try decoder.unkeyedContainer()
|
|
|
|
self.sensor0 = .init(byte: try container.decode(UInt8.self))
|
|
|
|
self.sensor1 = .init(byte: try container.decode(UInt8.self))
|
|
|
|
self.id = try container.decode(Int.self)
|
|
|
|
}
|
|
|
|
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
|
|
var container = encoder.unkeyedContainer()
|
|
|
|
try container.encode(sensor0.byte)
|
|
|
|
try container.encode(sensor1.byte)
|
|
|
|
try container.encode(id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension TemperatureMeasurement: Comparable {
|
|
|
|
|
|
|
|
static func < (lhs: TemperatureMeasurement, rhs: TemperatureMeasurement) -> Bool {
|
|
|
|
lhs.id < rhs.id
|
|
|
|
}
|
|
|
|
|
|
|
|
static func == (lhs: TemperatureMeasurement, rhs: TemperatureMeasurement) -> Bool {
|
|
|
|
lhs.id == rhs.id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension Array where Element == TemperatureMeasurement {
|
|
|
|
|
|
|
|
func maximumValue() -> Double? {
|
|
|
|
compactMap { $0.maximumValue }.max()
|
|
|
|
}
|
|
|
|
|
|
|
|
func minimumValue() -> Double? {
|
|
|
|
compactMap { $0.minimumValue }.min()
|
2023-06-05 13:05:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private extension TemperatureValue {
|
|
|
|
|
|
|
|
init(value: Double?) {
|
|
|
|
if let value {
|
|
|
|
self = .value(value)
|
|
|
|
} else {
|
|
|
|
self = .notFound
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension TemperatureMeasurement {
|
|
|
|
|
|
|
|
static let mockData: [TemperatureMeasurement] = {
|
|
|
|
let temps: [(Double?, Double?)] = [
|
|
|
|
(20, 14),
|
|
|
|
(20, 13.5),
|
|
|
|
(20.5, 13.5),
|
|
|
|
(20.5, 13.5),
|
|
|
|
(21, 14),
|
|
|
|
(21, 14),
|
|
|
|
(nil, 14.5),
|
|
|
|
(nil, 14),
|
|
|
|
(nil, 14.5),
|
|
|
|
(nil, 14),
|
|
|
|
(nil, 14),
|
|
|
|
(nil, 14.5),
|
|
|
|
(nil, 15),
|
|
|
|
(5.0, 15),
|
|
|
|
(4.5, 15.5),
|
|
|
|
(4.5, 16),
|
|
|
|
(4.0, 16.5),
|
|
|
|
(3.0, 17),
|
|
|
|
(3.0, 19),
|
|
|
|
(2.5, 20),
|
|
|
|
(2.5, 20.5),
|
|
|
|
(2.0, 20.5),
|
|
|
|
(1.0, 20.5),
|
|
|
|
(0.5, 20.5),
|
|
|
|
(0.0, 20),
|
|
|
|
(0.0, 20),
|
|
|
|
(-1.0, 21.0),
|
|
|
|
(-0.5, 21.0),
|
|
|
|
(-3.0, 21.0),
|
|
|
|
(-3.5, 20.5),
|
|
|
|
(-4.0, 20.5),
|
|
|
|
(-5.0, 20.0),
|
|
|
|
(-5.0, nil),
|
|
|
|
(-5.5, nil),
|
|
|
|
(-5.0, nil),
|
|
|
|
(-5.5, nil),
|
|
|
|
(-6.0, nil),
|
|
|
|
(-5.0, nil),
|
|
|
|
(nil, nil),
|
|
|
|
(nil, nil),
|
|
|
|
(nil, nil),
|
|
|
|
(-5.0, nil),
|
|
|
|
(-4.5, nil),
|
|
|
|
(-4.0, 23.0),
|
|
|
|
(5.0, 24.0),
|
|
|
|
(7.0, 25.0),
|
|
|
|
(8.0, 25.5),
|
|
|
|
(8.5, 25.5),
|
|
|
|
(10.0, 25.5),
|
|
|
|
(10.5, 24.0),
|
|
|
|
(10.5, 24.0),
|
|
|
|
(10.5, 24.5),
|
|
|
|
(12.0, 23.5),
|
|
|
|
(12.5, 24.0),
|
|
|
|
(12.0, 23.5),
|
|
|
|
(14.0, 24.0),
|
|
|
|
(15.0, 25.0),
|
|
|
|
(15.0, 25.0),
|
|
|
|
(15.5, 25.0),
|
|
|
|
(15.0, 25.0),
|
|
|
|
]
|
2023-06-08 09:52:20 +02:00
|
|
|
|
|
|
|
let seconds = Date().seconds
|
2023-06-05 13:05:57 +02:00
|
|
|
return temps.enumerated().map {
|
2023-06-08 09:52:20 +02:00
|
|
|
TemperatureMeasurement(
|
|
|
|
sensor0: .init(value: $0.element.0),
|
|
|
|
sensor1: .init(value: $0.element.1),
|
2023-06-11 21:57:07 +02:00
|
|
|
id: seconds + ($0.offset - temps.count) * 60)
|
2023-06-05 13:05:57 +02:00
|
|
|
}
|
|
|
|
}()
|
2023-06-03 08:15:00 +02:00
|
|
|
}
|