energykit

安装量: 236
排名: #3703

安装

npx skills add https://github.com/dpearson2699/swift-ios-skills --skill energykit
EnergyKit
Provide grid electricity forecasts to help users choose when to use electricity.
EnergyKit identifies times when there is relatively cleaner or less expensive
electricity on the grid, enabling apps to shift or reduce load accordingly.
Targets Swift 6.2 / iOS 26+.
Contents
Setup
Core Concepts
Querying Electricity Guidance
Working with Guidance Values
Energy Venues
Submitting Load Events
Electricity Insights
Common Mistakes
Review Checklist
References
Setup
Entitlement
EnergyKit requires the
com.apple.developer.energykit
entitlement. Add it
to your app's entitlements file.
Import
import
EnergyKit
Platform availability:
iOS 26+, iPadOS 26+.
Core Concepts
EnergyKit provides two main capabilities:
Electricity Guidance
-- time-weighted forecasts telling apps when
electricity is cleaner or cheaper, so devices can shift or reduce consumption
Load Events
-- telemetry from devices (EV chargers, HVAC) submitted back
to the system to track how well the app follows guidance
Key Types
Type
Role
ElectricityGuidance
Forecast data with weighted time intervals
ElectricityGuidance.Service
Interface for obtaining guidance data
ElectricityGuidance.Query
Query specifying shift or reduce action
ElectricityGuidance.Value
A time interval with a rating (0.0-1.0)
EnergyVenue
A physical location (home) registered for energy management
ElectricVehicleLoadEvent
Load event for EV charger telemetry
ElectricHVACLoadEvent
Load event for HVAC system telemetry
ElectricityInsightService
Service for querying energy/runtime insights
ElectricityInsightRecord
Historical energy data broken down by cleanliness/tariff
ElectricityInsightQuery
Query for historical insight data
Suggested Actions
Action
Use Case
.shift
Devices that can move consumption to a different time (EV charging)
.reduce
Devices that can lower consumption without stopping (HVAC setback)
Querying Electricity Guidance
Use
ElectricityGuidance.Service
to get a forecast stream for a venue.
import
EnergyKit
func
observeGuidance
(
venueID
:
UUID
)
async
throws
{
let
query
=
ElectricityGuidance
.
Query
(
suggestedAction
:
.
shift
)
let
service
=
ElectricityGuidance
.
sharedService
// Verify access pattern against Xcode 26 SDK
let
guidanceStream
=
service
.
guidance
(
using
:
query
,
at
:
venueID
)
for
try
await
guidance
in
guidanceStream
{
print
(
"Guidance token:
(
guidance
.
guidanceToken
)
"
)
print
(
"Interval:
(
guidance
.
interval
)
"
)
print
(
"Venue:
(
guidance
.
energyVenueID
)
"
)
// Check if rate plan information is available
if
guidance
.
options
.
contains
(
.
guidanceIncorporatesRatePlan
)
{
print
(
"Rate plan data incorporated"
)
}
if
guidance
.
options
.
contains
(
.
locationHasRatePlan
)
{
print
(
"Location has a rate plan"
)
}
processGuidanceValues
(
guidance
.
values
)
}
}
Working with Guidance Values
Each
ElectricityGuidance.Value
contains a time interval and a rating
from 0.0 to 1.0. Lower ratings indicate better times to use electricity.
func
processGuidanceValues
(
_
values
:
[
ElectricityGuidance
.
Value
]
)
{
for
value
in
values
{
let
interval
=
value
.
interval
let
rating
=
value
.
rating
// 0.0 (best) to 1.0 (worst)
print
(
"From
(
interval
.
start
)
to
(
interval
.
end
)
rating ( rating ) " ) } } // Find the best time to charge func bestChargingWindow ( in values : [ ElectricityGuidance . Value ] ) -> ElectricityGuidance . Value ? { values . min ( by : { $0 . rating < $1 . rating } ) } // Find all "good" windows below a threshold func goodWindows ( in values : [ ElectricityGuidance . Value ] , threshold : Double = 0.3 ) -> [ ElectricityGuidance . Value ] { values . filter { $0 . rating <= threshold } } Displaying Guidance in SwiftUI import SwiftUI import EnergyKit struct GuidanceTimelineView : View { let values : [ ElectricityGuidance . Value ] var body : some View { List ( values , id : \ . interval . start ) { value in HStack { VStack ( alignment : . leading ) { Text ( value . interval . start , style : . time ) Text ( value . interval . end , style : . time ) . foregroundStyle ( . secondary ) } Spacer ( ) RatingIndicator ( rating : value . rating ) } } } } struct RatingIndicator : View { let rating : Double var color : Color { if rating <= 0.3 { return . green } if rating <= 0.6 { return . yellow } return . red } var label : String { if rating <= 0.3 { return "Good" } if rating <= 0.6 { return "Fair" } return "Avoid" } var body : some View { Text ( label ) . padding ( . horizontal , 8 ) . padding ( . vertical , 4 ) . background ( color . opacity ( 0.2 ) ) . foregroundStyle ( color ) . clipShape ( Capsule ( ) ) } } Energy Venues An EnergyVenue represents a physical location registered for energy management. // List all venues func listVenues ( ) async throws -> [ EnergyVenue ] { try await EnergyVenue . venues ( ) } // Get a specific venue by ID func getVenue ( id : UUID ) async throws -> EnergyVenue { try await EnergyVenue . venue ( for : id ) } // Get a venue matching a HomeKit home func getVenueForHome ( homeID : UUID ) async throws -> EnergyVenue { try await EnergyVenue . venue ( matchingHomeUniqueIdentifier : homeID ) } Venue Properties let venue = try await EnergyVenue . venue ( for : venueID ) print ( "Venue ID: ( venue . id ) " ) print ( "Venue name: ( venue . name ) " ) Submitting Load Events Report device consumption data back to the system. This helps the system improve future guidance accuracy. EV Charger Load Events func submitEVChargingEvent ( at venue : EnergyVenue , guidanceToken : UUID , deviceID : String ) async throws { let session = ElectricVehicleLoadEvent . Session ( id : UUID ( ) , state : . begin , guidanceState : ElectricVehicleLoadEvent . Session . GuidanceState ( wasFollowingGuidance : true , guidanceToken : guidanceToken ) ) let measurement = ElectricVehicleLoadEvent . ElectricalMeasurement ( stateOfCharge : 45 , direction : . imported , power : Measurement ( value : 7.2 , unit : . kilowatts ) , energy : Measurement ( value : 0 , unit : . kilowattHours ) ) let event = ElectricVehicleLoadEvent ( timestamp : Date ( ) , measurement : measurement , session : session , deviceID : deviceID ) try await venue . submitEvents ( [ event ] ) } HVAC Load Events func submitHVACEvent ( at venue : EnergyVenue , guidanceToken : UUID , stage : Int , deviceID : String ) async throws { let session = ElectricHVACLoadEvent . Session ( id : UUID ( ) , state : . active , guidanceState : ElectricHVACLoadEvent . Session . GuidanceState ( wasFollowingGuidance : true , guidanceToken : guidanceToken ) ) let measurement = ElectricHVACLoadEvent . ElectricalMeasurement ( stage : stage ) let event = ElectricHVACLoadEvent ( timestamp : Date ( ) , measurement : measurement , session : session , deviceID : deviceID ) try await venue . submitEvents ( [ event ] ) } Session States State When to Use .begin Device starts consuming electricity .active Device is actively consuming (periodic updates) .end Device stops consuming electricity Electricity Insights Query historical energy and runtime data for devices using ElectricityInsightService . func queryEnergyInsights ( deviceID : String , venueID : UUID ) async throws { let query = ElectricityInsightQuery ( options : [ . cleanliness , . tariff ] , range : DateInterval ( start : Calendar . current . date ( byAdding : . day , value : - 7 , to : Date ( ) ) ! , end : Date ( ) ) , granularity : . daily , flowDirection : . imported ) let service = ElectricityInsightService . shared let stream = try await service . energyInsights ( forDeviceID : deviceID , using : query , atVenue : venueID ) for await record in stream { if let total = record . totalEnergy { print ( "Total: ( total ) " ) } if let cleaner = record . dataByGridCleanliness ? . cleaner { print ( "Cleaner: ( cleaner ) " ) } } } Use runtimeInsights(forDeviceID:using:atVenue:) for runtime data instead of energy. Granularity options: .hourly , .daily , .weekly , .monthly , .yearly . See references/energykit-patterns.md for full insight examples. Common Mistakes DON'T: Forget the EnergyKit entitlement Without the entitlement, all EnergyKit calls fail silently or throw errors. // WRONG: No entitlement configured let service = ElectricityGuidance . sharedService // Will fail // CORRECT: Add com.apple.developer.energykit to entitlements // Then use the service let service = ElectricityGuidance . sharedService DON'T: Ignore unsupported regions EnergyKit is not available in all regions. Handle the .unsupportedRegion and .guidanceUnavailable errors. // WRONG: Assume guidance is always available for try await guidance in service . guidance ( using : query , at : venueID ) { updateUI ( guidance ) } // CORRECT: Handle region-specific errors do { for try await guidance in service . guidance ( using : query , at : venueID ) { updateUI ( guidance ) } } catch let error as EnergyKitError { switch error { case . unsupportedRegion : showUnsupportedRegionMessage ( ) case . guidanceUnavailable : showGuidanceUnavailableMessage ( ) case . venueUnavailable : showNoVenueMessage ( ) case . permissionDenied : showPermissionDeniedMessage ( ) case . serviceUnavailable : retryLater ( ) case . rateLimitExceeded : backOff ( ) default : break } } DON'T: Discard the guidance token The guidanceToken links load events to the guidance that influenced them. Always store and pass it through to load event submissions. // WRONG: Ignore the guidance token for try await guidance in guidanceStream { startCharging ( ) } // CORRECT: Store the token for load events for try await guidance in guidanceStream { let token = guidance . guidanceToken startCharging ( followingGuidanceToken : token ) } DON'T: Submit load events without a session lifecycle Always submit .begin , then .active updates, then .end events. // WRONG: Only submit one event let event = ElectricVehicleLoadEvent ( / state: .active / ) try await venue . submitEvents ( [ event ] ) // CORRECT: Full session lifecycle try await venue . submitEvents ( [ beginEvent ] ) // ... periodic active events ... try await venue . submitEvents ( [ activeEvent ] ) // ... when done ... try await venue . submitEvents ( [ endEvent ] ) DON'T: Query guidance without a venue EnergyKit requires a venue ID. List venues first and select the appropriate one. // WRONG: Use a hardcoded UUID let fakeID = UUID ( ) service . guidance ( using : query , at : fakeID ) // Will fail // CORRECT: Discover venues first let venues = try await EnergyVenue . venues ( ) guard let venue = venues . first else { showNoVenueSetup ( ) return } let guidanceStream = service . guidance ( using : query , at : venue . id ) Review Checklist com.apple.developer.energykit entitlement added to the project EnergyKitError.unsupportedRegion handled with user-facing message EnergyKitError.permissionDenied handled gracefully Guidance token stored and passed to load event submissions Venues discovered via EnergyVenue.venues() before querying guidance Load event sessions follow .begin -> .active -> .end lifecycle ElectricityGuidance.Value.rating interpreted correctly (lower is better) SuggestedAction matches the device type ( .shift for EV, .reduce for HVAC) Insight queries use appropriate granularity for the time range Rate limiting handled via EnergyKitError.rateLimitExceeded Service unavailability handled with retry logic References Extended patterns (full app architecture, SwiftUI dashboard): references/energykit-patterns.md EnergyKit framework ElectricityGuidance ElectricityGuidance.Service ElectricityGuidance.Query ElectricityGuidance.Value EnergyVenue ElectricVehicleLoadEvent ElectricHVACLoadEvent ElectricityInsightService ElectricityInsightRecord ElectricityInsightQuery EnergyKitError Optimizing home electricity usage
返回排行榜