Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
061785d77b
|
|||
|
c4c4fed4bc
|
|||
|
e44c1c24c5
|
|||
|
df05898a65
|
|||
|
916fcb3584
|
|||
|
d9af0b8b30
|
|||
|
aa666d799a
|
|||
|
3825517dae
|
|||
|
c21695a37e
|
@@ -2,6 +2,7 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -4,7 +4,7 @@ name: Create and publish a Docker image
|
||||
# Configures this workflow to run every time a change is pushed to the branch called `release`.
|
||||
on:
|
||||
push:
|
||||
#branches: ['release']
|
||||
branches: ['release']
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
@@ -12,7 +12,7 @@ on:
|
||||
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
|
||||
env:
|
||||
REGISTRY: git.housh.dev
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
IMAGE_NAME: ${{ gitea.repository }}
|
||||
|
||||
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
|
||||
jobs:
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
password: ${{ secrets.CONTAINER_TOKEN }}
|
||||
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
@@ -53,14 +53,16 @@ jobs:
|
||||
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
|
||||
with:
|
||||
context: .
|
||||
file: docker/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)."
|
||||
- name: Generate artifact attestation
|
||||
uses: actions/attest-build-provenance@v1
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
subject-digest: ${{ steps.push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
# - name: Generate artifact attestation
|
||||
# uses: actions/attest-build-provenance@v1
|
||||
# with:
|
||||
# subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
# subject-digest: ${{ steps.push.outputs.digest }}
|
||||
# push-to-registry: true
|
||||
# github-token: ${{ secrets.CONTAINER_TOKEN }}
|
||||
|
||||
@@ -60,7 +60,10 @@ public struct TemperatureAndHumiditySensor: Identifiable, Sendable {
|
||||
!temperature.value.isNaN,
|
||||
!humidity.value.isNaN
|
||||
else { return nil }
|
||||
return try? await psychrometrics.dewPoint(.dryBulb(temperature, relativeHumidity: humidity))
|
||||
return try? await psychrometrics.dewPoint(.dryBulb(
|
||||
.fahrenheit(temperature.fahrenheit),
|
||||
relativeHumidity: humidity
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +76,7 @@ public struct TemperatureAndHumiditySensor: Identifiable, Sendable {
|
||||
!humidity.value.isNaN
|
||||
else { return nil }
|
||||
return try? await psychrometrics.enthalpy.moistAir(
|
||||
.dryBulb(temperature, relativeHumidity: humidity, altitude: altitude)
|
||||
.dryBulb(.fahrenheit(temperature.fahrenheit), relativeHumidity: humidity, altitude: altitude, units: .imperial)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -81,12 +84,11 @@ public struct TemperatureAndHumiditySensor: Identifiable, Sendable {
|
||||
/// Check whether any of the sensor values have changed and need processed.
|
||||
///
|
||||
/// - Note: Setting a value will set to both the temperature and humidity properties.
|
||||
public var needsProcessed: Bool {
|
||||
get { $temperature.needsProcessed || $humidity.needsProcessed }
|
||||
set {
|
||||
$temperature.needsProcessed = newValue
|
||||
$humidity.needsProcessed = newValue
|
||||
}
|
||||
public var needsProcessed: Bool { $temperature.needsProcessed || $humidity.needsProcessed }
|
||||
|
||||
public mutating func setHasProcessed() {
|
||||
$temperature.setHasProcessed()
|
||||
$humidity.setHasProcessed()
|
||||
}
|
||||
|
||||
/// Represents the different locations of a temperature and humidity sensor, which can
|
||||
|
||||
@@ -5,24 +5,20 @@
|
||||
@propertyWrapper
|
||||
public struct TrackedChanges<Value: Sendable>: Sendable {
|
||||
|
||||
/// The current tracking state.
|
||||
private var tracking: TrackingState
|
||||
|
||||
/// The current wrapped value.
|
||||
private var value: Value
|
||||
/// The current value wrapped in a tracking state.
|
||||
private var value: TrackingState
|
||||
|
||||
/// Used to check if a new value is equal to an old value.
|
||||
private var isEqual: @Sendable (Value, Value) -> Bool
|
||||
|
||||
/// Access to the underlying property that we are wrapping.
|
||||
public var wrappedValue: Value {
|
||||
get { value }
|
||||
get { value.currentValue }
|
||||
set {
|
||||
// Check if the new value is equal to the old value.
|
||||
guard !isEqual(newValue, value) else { return }
|
||||
guard !isEqual(newValue, value.currentValue) else { return }
|
||||
// If it's not equal then set it, as well as set the tracking to `.needsProcessed`.
|
||||
value = newValue
|
||||
tracking = .needsProcessed
|
||||
value = .needsProcessed(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,31 +33,42 @@ public struct TrackedChanges<Value: Sendable>: Sendable {
|
||||
needsProcessed: Bool = false,
|
||||
isEqual: @escaping @Sendable (Value, Value) -> Bool
|
||||
) {
|
||||
self.value = wrappedValue
|
||||
self.tracking = needsProcessed ? .needsProcessed : .hasProcessed
|
||||
self.value = .init(wrappedValue, needsProcessed: needsProcessed)
|
||||
self.isEqual = isEqual
|
||||
}
|
||||
|
||||
/// Represents whether a wrapped value has changed and needs processed or not.
|
||||
enum TrackingState {
|
||||
fileprivate enum TrackingState {
|
||||
case hasProcessed(Value)
|
||||
case needsProcessed(Value)
|
||||
|
||||
/// The state when nothing has changed and we've already processed the current value.
|
||||
case hasProcessed
|
||||
init(_ value: Value, needsProcessed: Bool) {
|
||||
if needsProcessed {
|
||||
self = .needsProcessed(value)
|
||||
} else {
|
||||
self = .hasProcessed(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// The state when the value has changed and has not been processed yet.
|
||||
case needsProcessed
|
||||
var currentValue: Value {
|
||||
switch self {
|
||||
case let .hasProcessed(value):
|
||||
return value
|
||||
case let .needsProcessed(value):
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
var needsProcessed: Bool {
|
||||
guard case .needsProcessed = self else { return false }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the value needs processed.
|
||||
public var needsProcessed: Bool {
|
||||
get { tracking == .needsProcessed }
|
||||
set {
|
||||
if newValue {
|
||||
tracking = .needsProcessed
|
||||
} else {
|
||||
tracking = .hasProcessed
|
||||
}
|
||||
}
|
||||
var needsProcessed: Bool { value.needsProcessed }
|
||||
|
||||
mutating func setHasProcessed() {
|
||||
value = .hasProcessed(value.currentValue)
|
||||
}
|
||||
|
||||
public var projectedValue: Self {
|
||||
@@ -95,6 +102,5 @@ extension TrackedChanges: Hashable where Value: Hashable {
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(wrappedValue)
|
||||
hasher.combine(needsProcessed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public actor SensorsService: Service {
|
||||
|
||||
private func publishUpdates() async throws {
|
||||
for sensor in sensors.filter(\.needsProcessed) {
|
||||
try await publish(sensor.dewPoint?.value, to: sensor.topics.dewPoint)
|
||||
try await publish(sensor.dewPoint?.fahrenheit, to: sensor.topics.dewPoint)
|
||||
try await publish(sensor.enthalpy?.value, to: sensor.topics.enthalpy)
|
||||
try sensors.hasProcessed(sensor)
|
||||
}
|
||||
@@ -172,7 +172,7 @@ private extension Array where Element == TemperatureAndHumiditySensor {
|
||||
guard let index = firstIndex(where: { $0.id == sensor.id }) else {
|
||||
throw SensorNotFoundError()
|
||||
}
|
||||
self[index].needsProcessed = false
|
||||
self[index].setHasProcessed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +207,6 @@ extension Humidity<Relative>: BufferInitalizable {
|
||||
extension Temperature<DryAir>: BufferInitalizable {
|
||||
init?(buffer: ByteBuffer) {
|
||||
guard let value = Double(buffer: buffer) else { return nil }
|
||||
self.init(value)
|
||||
self.init(value, units: .celsius)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user