mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Added dewPoint to Environment Metrics (#1377)
Co-authored-by: Jake-B <jake-b@users.noreply.github.com>
This commit is contained in:
parent
7a065277ea
commit
aaeecba532
7 changed files with 90 additions and 21 deletions
|
|
@ -1086,6 +1086,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"%f%%" : {
|
||||
|
||||
},
|
||||
"%lf" : {
|
||||
"localizations" : {
|
||||
|
|
|
|||
|
|
@ -52,4 +52,10 @@ public class TelemetryEntity: NSManagedObject, Identifiable {
|
|||
@ManagedAttribute<Float>(attributeName: "soilTemperature") public var soilTemperature: Float?
|
||||
@ManagedAttribute<UInt32>(attributeName: "soilMoisture") public var soilMoisture: UInt32?
|
||||
|
||||
public var dewPoint: Float? {
|
||||
guard let temp = self.temperature, let rh = self.relativeHumidity else {
|
||||
return nil
|
||||
}
|
||||
return Float(calculateDewPoint(temp: temp, relativeHumidity: rh, convertToLocale: false))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ class MetricsChartSeries: ObservableObject {
|
|||
// A closure that will provide the foreground style given the data set and overall chart range
|
||||
let foregroundStyle: (ClosedRange<Float>?) -> AnyShapeStyle?
|
||||
|
||||
// For drawing the lines in the chart
|
||||
let strokeStyle: StrokeStyle
|
||||
|
||||
// A closure that will provide the Chart Content for this series
|
||||
let chartBodyClosure:
|
||||
(MetricsChartSeries, ClosedRange<Float>?, TelemetryEntity) -> AnyChartContent? // Closure to render the chart
|
||||
|
|
@ -51,6 +54,7 @@ class MetricsChartSeries: ObservableObject {
|
|||
minumumYAxisSpan: Float? = nil,
|
||||
conversion: ((Value) -> Value)? = nil,
|
||||
visible: Bool = true,
|
||||
strokeStyle: StrokeStyle = StrokeStyle(lineWidth: 4),
|
||||
foregroundStyle: @escaping ((ClosedRange<Float>?) -> ForegroundStyle?) = { _ in nil },
|
||||
@ChartContentBuilder chartBody: @escaping (MetricsChartSeries, ClosedRange<Float>?, Date, Value) -> ChartBody?
|
||||
) {
|
||||
|
|
@ -62,7 +66,8 @@ class MetricsChartSeries: ObservableObject {
|
|||
self.initialYAxisRange = initialYAxisRange
|
||||
self.minumumYAxisSpan = minumumYAxisSpan
|
||||
self.visible = visible
|
||||
|
||||
self.strokeStyle = strokeStyle
|
||||
|
||||
// By saving these closures, MetricsChartSeries can be type agnostic
|
||||
// This is a less elegant form of type erasure, but doesn't require a new Any-type
|
||||
self.foregroundStyle = { range in foregroundStyle(range).map({ AnyShapeStyle($0) }) }
|
||||
|
|
|
|||
|
|
@ -90,12 +90,18 @@ struct LocalWeatherConditions: View {
|
|||
}
|
||||
|
||||
/// Magnus Formula
|
||||
func calculateDewPoint(temp: Float, relativeHumidity: Float) -> Double {
|
||||
func calculateDewPoint(temp: Float, relativeHumidity: Float, convertToLocale: Bool = true) -> Double {
|
||||
let a: Float = 17.27
|
||||
let b: Float = 237.7
|
||||
let alpha = ((a * temp) / (b + temp)) + log(relativeHumidity / 100.0)
|
||||
let dewPoint = (b * alpha) / (a - alpha)
|
||||
let dewPointUnit = Measurement<UnitTemperature>(value: Double(dewPoint), unit: .celsius)
|
||||
|
||||
if !convertToLocale {
|
||||
return Double(dewPoint)
|
||||
}
|
||||
|
||||
// Otherwise convert to locale units, default behavior
|
||||
let locale = NSLocale.current as NSLocale
|
||||
let localeUnit = locale.object(forKey: NSLocale.Key(rawValue: "kCFLocaleTemperatureUnitKey"))
|
||||
var format: UnitTemperature = .celsius
|
||||
|
|
|
|||
|
|
@ -39,6 +39,19 @@ extension MetricsColumnList {
|
|||
} ?? Text(verbatim: Constants.nilValueIndicator)
|
||||
}),
|
||||
|
||||
// Relative Humidity Series Configuration
|
||||
MetricsTableColumn(
|
||||
id: "dewPoint",
|
||||
keyPath: \.dewPoint,
|
||||
name: "Dew Point",
|
||||
abbreviatedName: "Dew",
|
||||
minWidth: 30, maxWidth: 45,
|
||||
tableBody: { _, dewPoint in
|
||||
dewPoint.map {
|
||||
Text("\($0.formattedTemperature())")
|
||||
} ?? Text(verbatim: Constants.nilValueIndicator)
|
||||
}),
|
||||
|
||||
// Barometric Pressure Series Configuration
|
||||
MetricsTableColumn(
|
||||
id: "barometricPressure",
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -76,11 +76,42 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
||||
MetricsChartSeries(
|
||||
id: "dewPoint",
|
||||
keyPath: \.dewPoint,
|
||||
name: "Dew Point",
|
||||
abbreviatedName: "Dew",
|
||||
minumumYAxisSpan: 50.0,
|
||||
conversion: { t in t.map { Float($0.localeTemperature()) } },
|
||||
strokeStyle: StrokeStyle(lineWidth: 4, dash: [2, 2]),
|
||||
foregroundStyle: { chartRange in
|
||||
let locale = NSLocale.current as NSLocale
|
||||
let localeUnit = locale.object(forKey: NSLocale.Key(rawValue: "kCFLocaleTemperatureUnitKey"))
|
||||
let format: UnitTemperature = localeUnit as? String ?? "Celsius" == "Fahrenheit" ? .fahrenheit : .celsius
|
||||
let lowerBound = chartRange.map { Double($0.lowerBound) } ?? 0.0
|
||||
let upperBound = chartRange.map { Double($0.upperBound) } ?? 100.0
|
||||
let stops: [Gradient.Stop] = generateStops(minTemp: lowerBound, maxTemp: upperBound, tempUnit: format, opacity: 1.0)
|
||||
return LinearGradient(stops: stops, startPoint: .bottom, endPoint: .top)
|
||||
},
|
||||
chartBody: { series, chartRange, time, dewPoint in
|
||||
if let dewPoint {
|
||||
LineMark(
|
||||
x: .value("Time", time),
|
||||
y: .value(
|
||||
series.abbreviatedName, dewPoint.localeTemperature())
|
||||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
||||
// Barometric Pressure Series Configuration
|
||||
MetricsChartSeries(
|
||||
id: "barometricPressure",
|
||||
|
|
@ -102,7 +133,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -130,7 +161,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -156,7 +187,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -182,7 +213,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -208,7 +239,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -234,7 +265,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -261,7 +292,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -288,7 +319,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
PointMark(
|
||||
x: .value("Time", time),
|
||||
|
|
@ -327,7 +358,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -353,7 +384,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -379,7 +410,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -405,7 +436,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -431,7 +462,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
}),
|
||||
|
|
@ -457,7 +488,7 @@ extension MetricsSeriesList {
|
|||
)
|
||||
.interpolationMethod(.catmullRom)
|
||||
.foregroundStyle(by: .value("Series", series.abbreviatedName))
|
||||
.lineStyle(StrokeStyle(lineWidth: 4))
|
||||
.lineStyle(series.strokeStyle)
|
||||
.alignsMarkStylesWithPlotArea()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -21,9 +21,14 @@ struct MetricsColumnDetail: View {
|
|||
Section("Chart") {
|
||||
ForEach(seriesList) { series in
|
||||
HStack {
|
||||
Circle()
|
||||
.fill(series.foregroundStyle(0.0...100.0) ?? AnyShapeStyle(.clear))
|
||||
.frame(width: 20.0, height: 20.0)
|
||||
Path { path in
|
||||
path.move(to: CGPoint(x: 10, y: 0))
|
||||
path.addLine(to: CGPoint(x: 10, y: 20))
|
||||
}
|
||||
.stroke(series.foregroundStyle(0.0...100.0) ?? AnyShapeStyle(.clear),
|
||||
style: series.strokeStyle)
|
||||
.frame(width: 20.0, height: 20.0)
|
||||
.rotationEffect(.degrees(90.0))
|
||||
Text(series.name)
|
||||
Spacer()
|
||||
if series.visible {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue