View in English

  • 메뉴 열기 메뉴 닫기
  • Apple Developer
검색
검색 닫기
  • Apple Developer
  • 뉴스
  • 둘러보기
  • 디자인
  • 개발
  • 배포
  • 지원
  • 계정
페이지에서만 검색

빠른 링크

5 빠른 링크

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 주제
  • 전체 비디오
  • 소개

WWDC25 컬렉션으로 돌아가기

  • 소개
  • 요약
  • 자막 전문
  • 코드
  • EnergyKit으로 가정용 전력 사용량 최적화하기

    앱에서 EnergyKit을 지원하여 사람들이 가정에서 전력 사용을 최적화하는 방법을 알아보세요. 전기가 더 깨끗하고 저렴할 때 가전제품을 사용하거나 전기차를 충전할 수 있습니다. 전력 사용량 피드백을 통해 온보딩, 충전 일정 생성 및 사람들에게 전력 사용량에 대한 인사이트를 되돌려주는 방법에 대해 자세히 살펴보세요.

    챕터

    • 0:00 - 서론
    • 2:08 - EnergyKit 온보딩
    • 3:28 - 충전 일정 생성
    • 7:35 - 인사이트
    • 14:58 - 다음 단계

    리소스

    • Apple 2030
    • Optimizing home electricity usage
      • HD 비디오
      • SD 비디오

    관련 비디오

    WWDC25

    • 백그라운드에서 작업 완료하기
    • SwiftUI에서 동시성 살펴보기
  • 비디오 검색…

    안녕하세요, Dakshil입니다 EnergyKit을 소개해 드리죠 전기는 하루 동안 다양한 곳에서 가정에 공급됩니다 태양열 및 풍력과 같은 재생 에너지도 있고 석탄 및 천연가스 같은 화석 연료로 만든 전기도 있죠 우리는 Home 앱 기능인 Grid Forecast 출시로 이를 시작했죠 이 앱으로 미국 본토 사용자들은 비교적 친환경적인 전기가 공급되는 시간대를 볼 수 있습니다 가정의 전기 사용량을 사용자의 경험에 직접 통합해 Home 앱 내 에너지 카테고리를 개인에 맞춰 실행 가능하게 만들었습니다 EnergyKit은 이 기능을 지원하고 당신은 이 프레임워크로 주거용 앱을 개발할 수 있죠 이를 통해 앱에 지역 전력망에 대한 통찰을 통합해 사용자의 전기 사용량을 절감 또는 조정하고 잠재 비용을 절감할 수 있죠 전기차 제조업체나 스마트 온도조절기 제조업체를 운영한다고 가정했을 때 EnergyKit은 더 친환경적이고 잠재적으로 저렴한 시간대를 우선시해 선택할 수 있습니다 전기차 제조업체는 EnergyKit으로 더 친환경적이고 잠재적으로 저렴한 시간대로 충전 일정을 조정할 수 있습니다 EnergyKit을 앱에 통합하는 방법을 알려 드리죠 전력 지침을 가져오고, 앱으로 전기차 충전 일정을 조정하는 방법을 알아보겠습니다 EnergyKit의 통찰로 멋진 사용자 경험을 만드는 방법도 보여드리겠습니다

    EnergyKit에 사용자를 등록하는 방법으로 시작해보죠

    EnergyKit을 앱에 통합하려면 먼저 사용자가 클린 에너지 충전 경험 선택에 동의하고 친환경 전력으로 충전하려는 각 위치를 선택해야 합니다 샘플 앱에는 전기차를 충전할 수 있는 충전 위치 목록이 포함돼 있습니다 이 위치에서 충전 시 사용자가 클린 에너지 충전 경험에 동의하는 토글을 추가했습니다

    EnergyVenue는 앱으로 제어되는 기기가 그리드에서 전기를 소비하고 소유자가 Home 앱 또는 EnergyKit 온보딩 흐름으로 Home을 설정한 실제 위치입니다 청정 에너지 충전 활성화 시 주변 위치의 EnergyVenue 목록을 가져옵니다 장소 선택 시, 해제할 때까지 선택한 장소 매핑을 충전 위치에 유지해야 하죠 장소 고유의 식별자를 로컬로 저장하는 것이 좋습니다 앱이 실행될 때마다 선택한 장소가 실제로 존재하는지 확인해야 합니다 이전에 저장한 장소 식별자로 선택한 장소를 불러올 수 있죠 청정 에너지 충전을 원하고 EnergyVenue를 선택했다면 이제 청정 에너지 충전 일정을 생성해야 합니다 청정 에너지 충전 일정을 생성하려면 일정을 안내할 예측 데이터가 필요하죠 이를 Electricity Guidance라고 합니다 이 지침은 Home 위치와 함께 탄소 배출량 또는 재생에너지 생성 여부 등의 그리드 정보를 조합해 생성되고 가능하면, 공공요금 계정 정보도 사용됩니다 지침 행동에는 두 가지 유형이 있습니다 바로 Reduce와 Shift죠 ‘Reduce’지침 행동은 스마트 온도조절기처럼 전력 사용량 절감을 위한 기기에 사용됩니다 ‘Shift’지침 행동은 전기차처럼 전기 사용량을 한 시점에서 다른 시점으로 전환하지만 동일한 전력을 사용하는 기기에 사용됩니다 그 예를 함께 살펴보죠 EnergyVenue의 전력 지침을 보여주는 그림이죠 지침 값은 Y축의 0~1 값으로 값이 낮을수록 전기가 더 친환경적이고 요금제 정보가 있다면 잠재적으로 저렴한 시간대를 의미합니다 여기에서 사용자는 Home 앱에서 공공요금 계정을 온보딩하고 전기 요금이 가장 비싼 오후 4~9시 요금제를 사용합니다 차는 오후 6:30쯤 충전됩니다 사용자의 충전 설정은 오전 9시쯤 차량의 충전이 끊기거나 완료된다는 사실을 알 수 있습니다

    충전 시간은 오후 6:30부터 다음 날 오전 9시까지라는 의미죠

    지침이 충전 일정에 적용되지 않으면 충전은 경제 및 환경적 측면에서 최적의 시간이 아닌 6:30부터 바로 시작될 수 있습니다 대신 사용자는 더 친환경적이고 잠재적으로 저렴한 시간대로 충전하도록 시간대를 선택해 충전 일정을 최적화할 수 있죠

    선택한 EnergyVenue에서 Electricity Guidance를 가져오는 방법을 살펴보죠 EnergyVenueManager에 streamGuidance 메서드를 먼저 추가합니다 업데이트할 때마다 guidance 변수에 저장합니다

    사용 사례에 맞는 지침을 가져올 쿼리를 생성해야 하죠 전기차의 경우 권장되는 작업 유형은 전력 사용량 변경입니다 EnergyVenue의 지침을 가져올 준비가 됐습니다 ElectricityGuidance엔 지침을 가져올 sharedService 헬퍼가 있죠 EnergyKit에서 업데이트된 지침을 받으면 업데이트되는 AsyncSequence가 반환됩니다 보다 자세한 정보는 ‘SwiftUI에서 동시성 발견하기’를 확인하세요 업데이트를 계속 들을 필요가 없다면 첫 가져오기 후 루프에서 빠져나올 수 있습니다 streamGuidance는 Task에서 호출 가능합니다 앱 백그라운드에서 업데이트해야 한다면 Background Task 핸들러에서 호출해야 합니다 당신의 앱에 대화형 충전 위젯이 있다면 앱이 실행하지 않을 때 위젯을 활용해 지침을 업데이트할 수 있죠 ‘백그라운드에서 작업 완료하기’에서 더 알아보세요

    이제 더 나은 충전 시간대를 찾기 위해 지침 값을 반복할 수 있습니다 EnergyKit Insights는 보기 쉬운 형태로 전기 정보를 제공합니다 제공된 통찰로 더 친환경적인 시간대에 차량 충전에 사용된 전기 양을 사람들에게 알릴 수 있어 가정용 전기 사용의 탄소 배출 절감에 도움이 되죠 차량의 전기 사용량은 그리드 청정도를 기준으로 세 가지 카테고리로 분류할 수 있습니다 바로 청정, 절감, 회피죠 상대적으로 저렴한 시간대에 사용되는 전기에 대해 안내할 수도 있습니다 차량의 전기 사용량은 가능하다면 전기 요금제로 분류되고 5가지로 나눌 수 있습니다 슈퍼 오프 피크, 오프 피크 및 부분 피크, 피크, 최대 피크죠

    요금제는 요금표라고도 합니다 그렇다면 통찰의 작동 방식은 어떠할까요? 통찰은 복합적인 요소의 영향을 받습니다 제공된 지침으로 전기를 전환 또는 절감하기 위해 사용하는 알고리즘은 제어 중인 기기가 더 친환경적이거나 저렴한 시간대에 전기를 사용하도록 결정합니다 기기가 전기를 소비하는 전기 그리드 상태는 전기 수요, 온라인 재생 가능 발전기, 그리드 배출량 등 다양한 요인의 영향을 받습니다 사용자가 Home 앱에서 공공요금 계정을 온보딩하고 시간제 요금제를 사용한다면 전기 사용량은 다양한 시간대로 구분돼 상대적인 전기 사용료를 확인할 수 있죠 그리고 가장 중요한 부분은 기기에서 전기를 소비한 방법과 시점이죠 이는 기기의 동작과 사용자의 상호작용 및 기기에 대한 앱의 지침 적용에 따라 결정됩니다 전기차 제조업체의 경우 차량의 충전 세션 행동으로 결정되겠죠 사용하는 전기의 청정도 및 상대 비용과 관련해 차량 충전에 대한 통찰 생성을 위해선 앱이 EnergyKit에 피드백을 제출해야 합니다 우리는 이 피드백을 LoadEvents라고 하죠 차량을 충전하고 충전 세션 도중 충전 상태가 변화할 때 주기적으로 이벤트를 생성해야 합니다 충전 세션이 시작되면 세션 시작 시 차량 상태를 나타내는 이벤트를 생성하세요 차량이 충전되면 이벤트가 주기적으로 생성됩니다 일정한 속도로 차량 충전 시 15분마다 한 번씩 이벤트를 생성하는 것이 좋습니다 세션 중단 새 지침의 적용으로 인한 충전 일정의 변경 또는 전력 사용량의 급변처럼 중요한 이벤트 발생 시 동일한 이벤트를 생성합니다 세션이 끝날 때에는 차량의 최종 상태를 보여주는 이벤트와 함께 세션이 종료됩니다 EnergyKit이 생성된 이벤트에 대한 통찰을 생성하려면 이를 EnergyKit에 제출해야 합니다 주기적으로 이벤트 발생 시마다 또는 일괄 제출하거나 충전 세션 종료 시 일괄 제출할 수 있죠 성능을 위해선 일괄 제출이 좋습니다 충전 세션 사이에는 제출하지 마세요 그럼 이벤트 생성 및 제출 방법을 살펴보죠 충전 세션에서 가장 중요한 정보는 배터리 충전 상태 주어진 인스턴스에서 소비되는 전기 충전 세션 시작 후 소비된 누적 에너지입니다 차량이 충전을 시작하면 세션이 시작됐다고 간주합니다

    이 이벤트는 충전 세션 시작 시 차량의 초기 상태를 보여주죠 지침 상태는 세션이 지침 토큰으로 표시된 전기 지침을 따르는 충전 일정에 따라 시작됐는지 나타냅니다 이 토큰은 지침을 가져온 휴대폰에 고유하고 해당 핸드폰에서 이벤트를 실제로 생성했고 생성하는 데 사용되죠 충전이 진행되면 세션은 활성 상태로 표시됩니다 충전 세션이 끝나면 종료 이벤트로 세션이 끝납니다 이 이벤트는 충전 종료 시 차량의 최종 상태를 보여줍니다 샘플 앱에서는 LoadEvents를 생성해 일괄 제출할 준비가 될 때까지 캐시에 저장합니다 이 일괄 이벤트는 차량이 충전된 EnergyVenue로 제출되죠 제출한 이벤트는 Apple의 개인정보 처리방침에 따라 기기 내 Core Data에 저장되고 CloudKit에 종단간 암호화로 백업됩니다 EnergyVenue 관련 HomeKit Home을 이미 공유하고 있는 모든 사람들과도 공유되죠 이제 통찰 생성을 위한 모든 정보가 준비됐습니다 통찰 검색을 위해 먼저 쿼리를 생성해 청정도 및 가능하면 상대 비용에 대한 통찰에 관심이 있다고 명시합니다 샘플 앱에서는 전날 전기 소비에 대한 요약 정보를 표시하고자 합니다 쿼리 생성 후 이전에 충전했던 장소에서의 차량에 대한 통찰을 가져올 수 있죠 AsyncStream이 반환되고 특정 일자에 대한 통찰에 관심 있었기 때문에 요청에 따라 스트림을 필터링할 수 있죠 가져온 통찰로 이제 요약을 생성할 수 있습니다 앱은 EnergyKit과 연동되었습니다 이 세션에서는 EnergyKit 연동의 기본을 살펴보았습니다 온보딩 과정에서는 앱과 상호작용하여 EnergyVenue를 선택하는 방법을 살펴봤죠 그런 다음 선택한 EnergyVenue 활용 방법, 전력 지침 가져오는 방법, 이를 사용해 충전 일정을 생성하는 방법을 확인했습니다

    충전 일정 생성 후 차량이 충전되는 동안 EnergyKit에 LoadEvents를 피드백으로 제출하는 것이 통찰 생성에 중요하다는 점을 배웠죠 마지막으로 가져온 지침 및 앱에서 제출한 피드백으로 통찰을 요청해 사용자 경험을 구축하는 방법을 살펴봤죠 이번 세션의 샘플 앱은 다운로드 가능하고 developer.apple.com/kr/에서 EnergyKit 문서를 확인할 수 있죠 Apple은 환경 보호에 최선을 다하고 있습니다 자세한 내용은 apple.com/kr/2030에서 확인하세요 EnergyKit으로 어떤 멋진 앱을 만드실지 기대하겠습니다

    • 3:13 - Retrive an EnergyVenue

      // Retrieve an EnergyVenue
      
      import EnergyKit
      import Foundation
      
      @Observable final class EnergyVenueManager  {
      
          let venue: EnergyVenue
      
          init?(venueID: UUID) async {
              guard let energyVenue = await EnergyVenue.venue(for: venueID) else {
                  return nil
              }
              venue = energyVenue
          }
      }
    • 6:03 - Fetch Electricity Guidance at a selected EnergyVenue

      // Fetch ElectricityGuidance
      
      import EnergyKit
      import Foundation
      
      @Observable final class EnergyVenueManager  {
          // The current active guidance.
          var guidance: ElectricityGuidance?
      
          fileprivate func streamGuidance(
              venueID: UUID,
              update: (_ guidance: ElectricityGuidance) -> Void
          ) async throws {
              let query = ElectricityGuidance.Query(suggestedAction: .shift)
              for try await currentGuidance in ElectricityGuidance.sharedService.guidance(
                  using: query,
                  at: venueID
              ) {
                  update(currentGuidance)
                	break
              }
          }
      }
    • 7:00 - Start monitoring Electricity Guidance

      // Fetch ElectricityGuidance
      
      import EnergyKit
      import Foundation
      
      @Observable final class EnergyVenueManager  {
          // The task used to stream guidance.
          private var streamGuidanceTask: Task<(), Error>?
      
          ///Start streaming guidance and store the value in the observed property 'guidance'.
          func startGuidanceMonitoring() {
             streamGuidanceTask?.cancel()
              streamGuidanceTask = Task.detached { [weak self] in
                  if let venueID = self?.venue.id {
                      try? await self?.streamGuidance(venueID: venueID) { guidance in
                          self?.guidance = guidance
                          if Task.isCancelled {
                              return
                          }
                      }
                  }
              }
          }
      }
    • 11:30 - Update charging measurements

      // Update charging measurements
      
      import EnergyKit
      
      // A controller that handles an electric vehicle
      @Observable class ElectricVehicleController {
          fileprivate func chargingMeasurement() -> ElectricVehicleLoadEvent.ElectricalMeasurement {
              let stateOfCharge = Int(configuration.state.stateOfCharge.rounded(.down))
              let power = Measurement<UnitPower>(
                  value: configuration.properties.chargingPower * 1000000,
                  unit: .milliwatts
              )
              let energy = Measurement<UnitEnergy>(
                  value: configuration.state.cummulativeEnergy * 1000000,
                  unit: .EnergyKit.milliwattHours
              )
              return ElectricVehicleLoadEvent.ElectricalMeasurement(
                  stateOfCharge: stateOfCharge,
                  direction: .imported,
                  power: power,
                  energy: energy
              )
          }
      }
    • 11:50 - Start a session

      // Start a session
      
      import EnergyKit
      
      // A controller that handles an electric vehicle
      @Observable class ElectricVehicleController {
          // The session
          var session: ElectricVehicleLoadEvent.Session?
      
          // The current guidance stored at the EV
          var currentGuidance: ElectricityGuidance
      
          // Whether the EV is following guidance
          var isFollowingGuidance: Bool = true
      
          fileprivate func beginSession() {
              session = ElectricVehicleLoadEvent.Session(
                  id: UUID(),
                  state: .begin,
                  guidanceState: .init(
                      wasFollowingGuidance: isFollowingGuidance,
                      guidanceToken: currentGuidance.guidanceToken
                  )
              )
          }
      }
    • 12:25 - Update a session

      // Update a session
      
      import EnergyKit
      
      // A controller that handles an electric vehicle
      @Observable class ElectricVehicleController {
          fileprivate func updateSession() {
              if let session {
                  self.session = ElectricVehicleLoadEvent.Session(
                      id: session.id,
                      state: .active,
                      guidanceState: .init(
                          wasFollowingGuidance:
                          isFollowingGuidance,
                          guidanceToken:
                          currentGuidance.guidanceToken
                      )
                  )
              }
          }
      }
    • 12:31 - End a session

      // End a session
      
      import EnergyKit
      
      // A controller that handles an electric vehicle.
      @Observable class ElectricVehicleController {
          fileprivate func endSession() {
              if let session {
                  self.session = ElectricVehicleLoadEvent.Session(
                      id: session.id,
                      state: .end,
                      guidanceState: .init(
                          wasFollowingGuidance:
                          isFollowingGuidance,
                          guidanceToken:
                          currentGuidance.guidanceToken
                      )
                  )
              }
          }
      }
    • 12:43 - Create a load event

      // Create a ElectricVehicleLoadEvent
      
      @Observable class ElectricVehicleController {
          fileprivate func createLoadEvent(
              sessionState: ElectricVehicleLoadEvent.Session.State
          ) {
              switch sessionState {
              case .begin:
                  beginSession()
              case .active:
                  updateSession()
              case .end:
                  endSession()
              @unknown default:
                  fatalError()
              }
              if let session {
                  let event = ElectricVehicleLoadEvent(
                      timestamp: configuration.state.timestamp,
                      measurement: chargingMeasurement(),
                      session: session,
                      deviceID: configuration.properties.vehicleID
                  )
                 events.append(event)
              }
          }
      }
    • 12:50 - Submit events

      // Submit events
      
      import EnergyKit
      
      // A controller that handles an electric vehicle
      @Observable class ElectricVehicleController {
          // EnergyVenue
          // The venue at which the EV uses energy
          var currentVenue: EnergyVenue
      
          // Electric EV Events
          // The list of generated EV load events
          var events = [ElectricVehicleLoadEvent]()
          
          func submitEvents() async throws {
              try await currentVenue.submitEvents(events)
          }
      }
    • 13:25 - Create an insight query

      // Create an insight query
      
      import EnergyKit
      
      @Observable final class EnergyVenueManager  {
          func createInsightsQuery(on date: Date) -> ElectricityInsightQuery {
              return ElectricityInsightQuery(
                  options: .cleanliness.union(.tariff),
                  range: self.dayInterval(date: date),
                  granularity: .daily,
                  flowDirection: .imported
              )
          }
      }
    • 13:43 - Request insights

      // Request an insights
      
      import EnergyKit
      
      @Observable final class EnergyVenueManager  {
          func generateInsights(for vehicleIdentifier: String, on date: Date) async throws ->
    ElectricityInsightRecord<Measurement<UnitEnergy>>? {
              let query = createInsightsQuery(on: date)
              return try await ElectricityInsightService.shared.energyInsights(
                  forDeviceID: vehicleIdentifier,
                  using: query,
                  atVenue: self.venue.id
              ).first { record in
                  return record.range.start == query.range.start
              }
          }
      }
    • 0:00 - 서론
    • EnergyKit 프레임워크를 사용하면 지역 전력망 통찰을 앱에 통합하여 사람들이 스마트 온도 조절 기기와 같은 기기를 사용하거나 전기 자동차를 충전할 때 사용량을 줄이고, 비용을 절감하며, 더 깨끗한 에너지원을 우선시할 수 있습니다.

    • 2:08 - EnergyKit 온보딩
    • EnergyKit을 온보딩하려면 사용자는 특정 위치에서 청정에너지 충전을 옵트인해야 합니다. 앱은 위치(에너지 장소라고 함)를 검색하고 해당 식별자를 저장합니다.

    • 3:28 - 충전 일정 생성
    • EnergyKit은 위치, 전력망 정보, 공공요금 데이터를 기반으로 전력 지침을 제공하여 청정에너지 충전 일정을 수립합니다. (스마트 온도 조절 기기와 같은 기기의 경우) ‘절감’ 동작이나 (전기 자동차 충전과 같은 용도의 경우) ‘이동’ 동작을 제안할 수 있습니다. 전력 지침은 더 깨끗하고 저렴한 오프 피크 시간대를 우선시하여 비용과 환경에 미치는 영향을 최적화합니다.

    • 7:35 - 인사이트
    • EnergyKit 인사이트는 사용자에게 전력 정보를 보다 간편하게 제공하는 데 도움이 되며 전력망 청정도에 따라 전력 사용량을 분류할 수 있습니다. 전기 자동차 제조업체가 통찰을 얻을 수 있도록 앱은 충전 세션을 진행하는 동안 진행 상황을 추적하는 부하 이벤트 형태로 EnergyKit에 피드백을 제공합니다. 이러한 이벤트를 일괄 처리하고 제출함으로써 EnergyKit은 충전 데이터를 정확하게 분석할 수 있습니다.

    • 14:58 - 다음 단계
    • 앱에 EnergyKit을 도입하여 전력 사용량을 관리하세요. 보다 자세한 내용은 이 세션과 함께 제공되는 샘플 코드를 참고하세요.

Developer Footer

  • 비디오
  • WWDC25
  • EnergyKit으로 가정용 전력 사용량 최적화하기
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • 앱 확장 프로그램
    • App Store
    • 오디오 및 비디오(영문)
    • 증강 현실
    • 디자인
    • 배포
    • 교육
    • 서체(영문)
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 머신 러닝 및 AI
    • 오픈 소스(영문)
    • 보안
    • Safari 및 웹(영문)
    메뉴 열기 메뉴 닫기
    • 문서(영문)
    • 튜토리얼
    • 다운로드(영문)
    • 포럼(영문)
    • 비디오
    메뉴 열기 메뉴 닫기
    • 지원 문서
    • 문의하기
    • 버그 보고
    • 시스템 상태(영문)
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, 식별자 및 프로파일(영문)
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(영문)
    • News Partner Program(영문)
    • Video Partner Program(영문)
    • Security Bounty Program(영문)
    • Security Research Device Program(영문)
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Center
    • App Store 어워드(영문)
    • Apple 디자인 어워드
    • Apple Developer Academy(영문)
    • WWDC
    Apple Developer 앱 받기
    Copyright © 2025 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침