공간 에너지 관리 시스템을 소개할 때 보여 드리는 화면은 단순합니다. 공간 카드가 나열되어 있고, 카드를 누르면 조명과 에어컨 스위치가 나오고, 옆 메뉴에는 이번 달 전기 사용량 그래프가 있습니다.
그래서 이런 질문을 자주 받습니다. "그 버튼을 누르면 실제로 무슨 일이 일어납니까?" "센서 값은 어떻게 화면까지 옵니까?" "인터넷이 잠깐 끊기면 어떻게 됩니까?"
이 글은 그 질문에 대한 답입니다. 저희가 직접 개발해 운영하고 있는 건물 에너지 절감 솔루션 B-Saver를 기준으로, 화면 뒤에서 데이터가 움직이는 경로를 하나씩 따라가 봅니다. B-Saver는 2025년 4월에 개발을 시작해 현재 조명·스위치·냉난방 등 200대가 넘는 기기를 제어하고 있습니다.
미리 말씀드리면, 이 시스템에서 데이터가 움직이는 경로는 하나가 아닙니다. 상태가 올라오는 길, 명령이 내려가는 길, 자동화가 판단하는 길, 전력 데이터가 들어오는 길이 각각 따로 있습니다. 경로를 나눠서 보면 구조가 훨씬 쉽게 읽힙니다.
1. 전체 구조: 네 개의 층
시스템은 아래에서 위로 네 개의 층으로 나뉩니다.
| 층 | 구성 | 맡은 일 |
|---|---|---|
| 현장 | 조명, 스위치, 에어컨, 도어락, 온습도·재실 센서 | 실제로 켜지고 꺼지며 값을 측정 |
| 허브 | 현장에 설치한 Home Assistant | 제조사가 다른 기기를 같은 형식으로 묶음 |
| 수집·제어 | 허브와 상시 연결된 서비스, 명령 대기열 | 상태 변화를 받아 저장하고 명령을 순서대로 전달 |
| 업무 | 시설·자동화·에너지·예약·알림 서비스와 대시보드 | 공간, 시나리오, 요금, 예약 같은 운영 단위를 다룸 |
허브를 두는 이유
현장의 기기는 제조사마다 통신 방식이 다릅니다. 조명은 Zigbee로, 에어컨은 적외선 리모컨 신호로, 도어락은 제조사 서버를 거쳐 제어하는 식입니다. 이 차이를 상위 시스템이 직접 다루기 시작하면 기기 종류가 하나 늘 때마다 코드가 늘어납니다.
Home Assistant는 이 차이를 엔티티라는 하나의 형식으로 정리해 줍니다. 조명이든 에어컨이든 "이름, 현재 상태, 속성"으로 표현되고, 제어도 "어떤 엔티티에 어떤 동작을 요청한다"는 같은 형식으로 보냅니다. 상위 시스템은 엔티티만 알면 됩니다. 조명 제조사가 바뀌어도 대시보드 쪽 코드는 그대로입니다.
기기가 아니라 공간이 기준입니다
허브가 주는 것은 엔티티 목록입니다. 수백 개의 엔티티가 한 줄로 나열된 목록은 운영에 쓰기 어렵습니다. 관리자가 내리는 지시는 "조명 12번을 꺼 달라"가 아니라 "3층 회의실을 정리해 달라"이기 때문입니다.
그래서 건물, 층, 공간의 계층을 먼저 만들고 엔티티를 공간에 배치합니다. 등록 화면에서 허브가 가진 엔티티를 불러오면 제어 가능한 종류(조명, 스위치, 냉난방, 커버, 도어락 등)와 센서만 추려서 보여 주고, 이미 등록한 것은 목록에서 빠집니다. 관리자는 엔티티를 골라 공간에 넣기만 하면 됩니다.
공간에는 현재 상태라는 값이 붙습니다. "입실", "청소중" 같은 운영 상태입니다. 뒤에서 보겠지만 이 값은 화면 표시용에 그치지 않고 자동화의 판단 조건으로도 쓰입니다.
2. 상태가 올라오는 길
현장에서 일어난 변화가 화면에 표시되기까지의 경로입니다. 재실 센서가 사람을 감지한 순간을 예로 들어 보겠습니다.
고객사 허브마다 연결을 하나씩 유지합니다
수집 서비스는 등록된 허브마다 웹소켓 연결을 하나씩 열어 둡니다. 허브에 주기적으로 물어보는 방식이 아니라, 연결을 유지한 채 변화를 받는 방식입니다.
연결 대상 목록은 60초마다 다시 확인합니다. 새 고객사의 허브가 등록되면 다음 확인 때 연결이 추가되고, 허브 주소나 인증 정보가 바뀌면 연결을 다시 맺습니다. 등록된 기기가 하나도 없는 허브에는 연결하지 않습니다.
변화만 골라냅니다
허브가 보내는 것은 엔티티 전체의 최신 값입니다. 수집 서비스는 직전 값과 비교해 상태가 달라진 엔티티만 이벤트로 만듭니다. 대부분의 기기는 켜짐·꺼짐 같은 상태 값만 비교하지만, 에어컨은 예외입니다. 전원은 그대로인데 설정 온도나 풍량, 운전 모드만 바뀌는 경우가 많아서 이 속성들의 변화도 함께 봅니다.
연결 직후 처음 받은 값은 비교 대상이 없으므로 이벤트로 만들지 않습니다. 재시작할 때마다 모든 기기에서 "상태가 바뀌었다"는 이벤트가 쏟아지는 것을 막기 위해서입니다.
모아서 보냅니다
이벤트를 한 건씩 저장 요청으로 보내면, 건물 전체의 조명을 한꺼번에 끌 때 요청 수백 건이 동시에 발생합니다. 그래서 이벤트를 50건이 차거나 1초가 지나면 한 묶음으로 전송합니다. 화면 반영이 최대 1초 늦어지는 대신 서버가 받는 요청 수가 크게 줄어듭니다.
저장하는 방식은 기기와 센서가 다릅니다
- 기기 — 상태가 바뀔 때마다 이력을 한 줄 남기고, 기기의 현재 상태와 마지막 통신 시각, 온라인 여부를 갱신합니다
- 센서 — 현재 값을 갱신하고, 숫자로 바꿀 수 있는 값은 시계열 측정값으로 쌓습니다. 재실 센서의 "감지됨"은 1, "감지 안 됨"은 0으로 저장합니다
허브가 "응답 없음"으로 보고한 값은 측정값으로 저장하지 않습니다. 통신이 끊긴 구간이 0으로 기록되면 나중에 그래프에서 실제 0과 구분할 수 없기 때문입니다.
화면으로 밀어 줍니다
저장이 끝나면 실시간 전달 서비스가 해당 기기·센서를 보고 있는 브라우저에 이벤트를 보냅니다. 브라우저는 이벤트를 받으면 0.5초를 기다렸다가 공간 요약을 한 번 다시 읽습니다. 조명 열 개가 연달아 꺼질 때 열 번 다시 읽지 않기 위한 간격입니다.
실시간 연결만 믿지는 않습니다. 화면이 보이는 동안에는 30초마다 한 번씩 요약을 다시 읽습니다. 이벤트 하나가 중간에 사라지더라도 30초 안에는 화면이 실제와 맞춰집니다.
끊겼을 때
허브와의 연결이 끊기면 5초 뒤에 다시 시도하고, 실패할 때마다 간격을 두 배로 늘립니다. 간격은 최대 5분까지만 늘어납니다. 현장 인터넷이 몇 시간 끊긴 상황에서 5초마다 재시도하면 복구 시점에 불필요한 부하만 만들기 때문입니다.
허브에 처음 연결할 때는 변화를 기다리지 않고 전체 상태를 한 번 읽어 와 저장합니다. 연결 전에 이미 켜져 있던 기기를 화면에 반영하기 위한 절차입니다.
3. 명령이 내려가는 길
이번에는 반대 방향입니다. 관리자가 화면에서 에어컨을 켰을 때 일어나는 일입니다.
요청을 받는 일과 실행하는 일을 나눕니다
버튼을 누르면 서버는 그 자리에서 허브를 호출하지 않습니다. 권한을 확인한 뒤 명령을 대기열에 넣고 바로 응답합니다. 화면은 응답을 받는 즉시 스위치를 켜진 상태로 바꿉니다.
실행은 대기열을 지켜보는 작업자가 맡습니다. 이렇게 나눈 이유는 허브 응답 시간이 일정하지 않기 때문입니다. 적외선으로 제어하는 에어컨은 명령이 반영되는 데 1초 넘게 걸리기도 합니다. 사용자의 요청이 그 시간 동안 붙잡혀 있으면 화면이 멈춘 것처럼 보이고, 버튼을 여러 번 누르게 됩니다.
같은 기기로 가는 명령은 줄을 세웁니다
작업자는 여러 명령을 동시에 처리하지만, 같은 기기로 가는 명령은 한 번에 하나만 보냅니다. 명령을 보낸 뒤에는 1.2초의 안착 시간을 두고 다음 명령을 허용합니다.
이 장치는 운영 중에 추가했습니다. 적외선 에어컨에 "전원 켜기"와 "온도 24도"를 거의 동시에 보내면 뒤 신호가 앞 신호와 겹쳐 둘 중 하나가 무시되는 일이 있었습니다. 화면에서는 두 명령 모두 성공으로 보이는데 실제 에어컨은 온도만 바뀌고 켜지지 않는 식입니다.
실행한 뒤에 다시 확인합니다
허브가 "명령을 받았다"고 응답한 것과 기기가 실제로 바뀐 것은 다릅니다. 그래서 명령을 보낸 뒤 허브에 기기의 상태를 다시 물어봅니다. 0.5초 간격으로 최대 6초 동안 확인하고, 숫자 값에는 허용 오차를 둡니다. 설정 온도는 0.5도, 밝기는 1% 이내면 반영된 것으로 봅니다.
| 단계 | 기준 |
|---|---|
| 허브 호출 제한 시간 | 10초 |
| 호출 실패 시 재시도 | 3회, 간격을 늘려 가며 |
| 명령 후 안착 시간 | 1.2초 |
| 반영 확인 | 0.5초 간격, 최대 6초 |
확인에 실패했다고 해서 곧바로 실패로 기록하지는 않습니다. 허브가 명령을 정상적으로 받았다면 결과는 성공으로 두고, "반영을 확인하지 못함"이라는 경고를 함께 남깁니다. 상태 보고가 느린 기기가 있어서, 확인 실패를 모두 실패로 처리하면 정상 동작한 제어까지 실패 통계에 섞입니다.
최종 확정은 2장의 경로가 맡습니다. 기기가 실제로 바뀌면 허브가 상태 변화를 올려 보내고, 그 값이 화면에 반영됩니다. 화면이 먼저 표시한 예상 값과 실제 값이 다르면 이때 바로잡힙니다.
모든 명령은 기록됩니다
제어 한 건마다 기기, 동작, 이전 값과 이후 값, 결과, 그리고 출처를 남깁니다. 출처는 수동, 시나리오, 스케줄, 조건 자동화, 냉난방 자동 제어로 구분합니다. "새벽에 회의실 에어컨이 왜 켜졌느냐"는 질문에 답하려면 누가 눌렀는지뿐 아니라 어떤 규칙이 실행했는지가 남아 있어야 합니다.
아래는 이 경로가 실제로 쓰이는 공간 제어 화면의 구성입니다.
4. 사람이 누르지 않아도 움직이는 부분
수동 제어만으로는 에너지가 줄지 않습니다. 끄는 것을 잊는 일이 반복되기 때문입니다. 시스템이 스스로 명령을 만드는 경로는 네 가지입니다. 어느 경로든 만들어진 명령은 3장의 대기열로 들어가 같은 절차로 실행됩니다.
시나리오: 여러 동작을 순서대로
시나리오는 기기 동작을 순서대로 묶은 것입니다. 각 동작에는 0~60초의 지연을 줄 수 있습니다. 실행기는 동작 하나를 대기열에 넣고 끝날 때까지 기다린 다음, 지정한 시간만큼 쉬고 다음 동작으로 넘어갑니다.
중간에 한 동작이 실패해도 멈추지 않고 끝까지 진행합니다. 결과는 성공, 부분 성공, 실패 세 가지로 남기고 성공·실패 건수를 함께 기록합니다. 조명 여덟 개 중 하나가 응답하지 않았다고 냉방 종료까지 건너뛰면 손해가 더 크기 때문입니다.
시나리오에는 목표 상태를 붙일 수 있습니다. "청소 시작" 시나리오를 실행하면 공간 상태가 "청소중"으로 바뀌고, 종료 시각을 지정해 두면 그 시각에 상태가 풀리거나 다음 시나리오가 이어서 실행됩니다.
스케줄: 정해진 시각에
스케줄은 시각과 반복 규칙(매일, 평일, 주말, 요일 지정)으로 시나리오를 실행합니다. 스케줄러는 1분마다 실행 시각이 된 항목을 찾아 처리합니다. 같은 주기로 공간 상태의 만료와 예약 퇴실 시각도 함께 확인합니다.
조건 실행: 센서와 기기 상태에 따라
"재실 센서가 15분 동안 비어 있으면 조명과 냉방을 끈다" 같은 규칙입니다. 판정은 다음 순서로 이루어집니다.
- 조건이 맞는 순간만 잡습니다. 조건이 "맞지 않음"에서 "맞음"으로 바뀌는 순간에만 반응합니다. 온도가 28도를 넘은 상태가 한 시간 이어져도 규칙은 한 번만 실행됩니다
- 지속 시간을 봅니다. 지속 시간을 지정하면 그 시간 동안 조건이 유지되어야 실행합니다. 중간에 조건이 풀리면 타이머를 취소합니다. 사람이 잠깐 자리를 비운 것과 퇴실한 것을 구분하는 장치입니다
- 공간 상태를 확인합니다. "청소중인 공간에서는 실행하지 않는다"처럼 공간 상태를 조건으로 걸 수 있습니다
- 재실행 대기 시간을 확인합니다. 한 번 실행한 규칙은 최소 60초, 길게는 4시간까지 다시 실행하지 않도록 설정합니다. 센서 값이 경계에서 오르내릴 때 기기가 반복해서 켜지고 꺼지는 것을 막습니다
이벤트를 놓쳤을 때를 대비해 20초마다 조건을 다시 평가하는 보조 경로도 둡니다. 기기가 통신 두절 상태가 된 것 자체를 조건으로 쓸 수도 있어서, "냉장 설비가 5분 이상 응답하지 않으면 알림"처럼 장애 감지 규칙도 같은 구조로 만듭니다.
예약 연동: 입실과 퇴실에 맞춰
숙박·공유 공간에서는 예약이 가장 정확한 재실 정보입니다. 예약마다 입실 시나리오와 퇴실 시나리오를 지정해 두면, 키오스크나 관리자 화면에서 입실 처리를 하는 순간 입실 시나리오가 실행되고 공간 상태가 "입실"로 바뀝니다. 퇴실 시각이 지나면 스케줄러가 자동으로 퇴실 처리를 하고 퇴실 시나리오를 실행합니다.
같은 예약을 두 경로가 동시에 처리하지 않도록, 상태 전환을 먼저 확정한 쪽만 시나리오를 실행합니다. 이 순서가 없으면 퇴실 시나리오가 두 번 실행되어 제어 이력이 중복됩니다.
냉난방 자동 제어: 5분마다 조금씩
에어컨은 켜고 끄는 것보다 설정 온도를 조정하는 쪽이 절감 효과가 큽니다. 냉난방 자동 제어는 5분 주기로 공간별 상태를 보고 설정 온도를 조정합니다.
| 항목 | 동작 |
|---|---|
| 조정 폭 | 한 번에 1도씩, 18~28도 범위 안에서 |
| 공실 판단 | 15분 동안 비어 있으면 공실로 보고 완화 운전 또는 정지 |
| 운영 시간 | 요일별 운영 시간 밖에서는 정지 |
| 예약 연동 | 입실 60분 전부터 미리 냉난방 |
| 수동 조작 | 사람이 직접 조작하면 30분 동안 자동 제어가 개입하지 않음 |
마지막 항목이 중요합니다. 자동 제어가 사람의 조작을 바로 되돌리면 이용자는 시스템과 싸우게 되고, 결국 자동 제어를 꺼 달라고 요청합니다. 사람이 손댄 뒤에는 일정 시간 물러나 있는 편이 자동화를 오래 유지하는 방법입니다.
5. 전력 데이터가 들어오는 길
지금까지는 기기 쪽 이야기였습니다. 에너지 관리가 되려면 "그래서 전기를 얼마나 썼는가"가 같은 시스템 안에 있어야 합니다.
한국전력 계량 데이터를 가져옵니다
건물에 계기 설정을 등록하면 한국전력의 계량 데이터를 연동합니다. 가져오는 데이터는 두 종류입니다.
- 15분 단위 사용량 — 하루를 96개 구간으로 나눈 값. 언제 많이 썼는지를 보는 데이터
- 월별 요금 — 기본요금, 전력량요금, 청구금액, 경부하·중간부하·최대부하 시간대별 사용량
수집은 매일 아침 한 번 자동으로 실행됩니다. 이때 전날 하루만 가져오지 않고 최근 3일 치를 다시 가져옵니다. 계량 데이터는 늦게 확정되는 구간이 있어서, 하루치만 받으면 빈 구간이 그대로 남습니다. 월별 요금도 같은 이유로 직전 두 달을 다시 확인합니다.
시스템 도입 이전 기간은 한전에서 내려받은 파일을 올려 채웁니다. 비교할 과거 데이터가 있어야 도입 후의 변화를 말할 수 있으므로, 초기 설정에서 거의 항상 거치는 절차입니다.
화면의 숫자는 이렇게 계산됩니다
- 현재 사용 전력 — 가장 최근 15분 구간의 사용량에 4를 곱해 시간당 값으로 환산합니다
- 이번 달 사용량 — 경부하·중간부하·최대부하 사용량의 합
- 비교 기준 — 지난달, 그리고 작년 같은 달. 냉난방 부하는 계절을 타기 때문에 지난달과의 비교만으로는 판단하기 어렵습니다
- 절감 금액 — 지난달 청구금액보다 줄어든 만큼
제어 기록과 나란히 봅니다
전력 데이터와 제어 이력이 같은 시스템에 있으면 질문의 형태가 달라집니다. "지난주 화요일 오후에 사용량이 튄 이유"를 찾을 때, 그 시간대의 15분 사용량과 같은 시간대의 제어 이력을 함께 열어 봅니다. 어느 공간의 냉방이 몇 시에 누구에 의해 켜졌는지가 출처와 함께 남아 있기 때문에, 원인을 추정이 아니라 기록에서 찾습니다.
6. 계정이 없는 사람의 경로
마지막 경로는 관리자가 아닌 사람을 위한 것입니다. 객실 투숙객, 회의실 이용자, 청소 담당자는 대시보드 계정이 없습니다. 그렇다고 이들이 기기를 전혀 조작하지 못하면 벽 스위치와 리모컨으로 돌아가게 되고, 그 조작은 기록에 남지 않습니다.
공간마다 QR 코드를 발급하고, 접근 권한을 따로 만듭니다. 접근 권한에는 여섯 자리 코드, 실행할 수 있는 시나리오와 기기 목록, 만료 시각이 들어갑니다. 같은 공간이라도 투숙객용 권한과 청소 담당자용 권한을 다르게 줄 수 있습니다.
- 투숙객은 조명과 냉난방 시나리오만 실행합니다
- 청소 담당자는 "청소 시작" 시나리오를 실행하고, 작업이 끝나면 완료를 눌러 소요 시간을 남깁니다
- 유실물이나 파손을 발견하면 사진과 함께 신고합니다
코드 입력이 20회 틀리면 그 공간의 QR 접근을 10분 동안 잠급니다. QR로 실행한 동작도 3장의 대기열을 거치고, 제어 이력에는 어떤 접근 권한으로 실행했는지가 남습니다.
7. 이 구조에서 얻은 것
경로별로 내린 결정과 그 이유를 한 표로 정리하면 다음과 같습니다.
| 결정 | 이유 |
|---|---|
| 허브를 제어 계층으로 둔다 | 제조사가 바뀌어도 상위 시스템을 고치지 않기 위해 |
| 상태는 연결을 유지해 받는다 | 주기 조회로는 변화 시점을 놓치고 요청 수만 늘어남 |
| 실시간 전달과 30초 재조회를 함께 쓴다 | 이벤트 하나가 사라져도 화면이 실제와 어긋난 채 남지 않게 |
| 명령은 대기열에 넣고 바로 응답한다 | 허브 응답 시간이 화면 반응 속도를 좌우하지 않게 |
| 같은 기기의 명령은 직렬로 보낸다 | 신호가 겹쳐 명령이 무시되는 것을 막기 위해 |
| 실행 뒤 실제 상태를 다시 확인한다 | "보냈다"와 "바뀌었다"를 구분하기 위해 |
| 조건은 바뀌는 순간에만 반응한다 | 같은 규칙이 조건이 유지되는 내내 반복 실행되지 않게 |
| 수동 조작 뒤에는 자동 제어가 물러난다 | 이용자가 자동화를 꺼 버리지 않게 |
| 계량 데이터는 며칠 치를 겹쳐 다시 받는다 | 늦게 확정되는 구간을 채우기 위해 |
| 모든 제어에 출처를 남긴다 | 누가, 어떤 규칙이 실행했는지 나중에 답하기 위해 |
서비스를 나눈 방식
초기에는 하나의 웹 애플리케이션이 모든 것을 처리했습니다. 기능이 늘면서 시설, 기기, 자동화, 에너지, 예약, 계정, 알림의 일곱 영역으로 서비스를 나누고, 영역마다 데이터베이스를 따로 두었습니다.
이때 기준으로 삼은 것은 화면이 호출하는 주소와 응답 형식을 바꾸지 않는 것이었습니다. 대시보드는 예전과 같은 요청을 보내고, 요청을 받은 쪽이 해당 영역의 서비스로 전달합니다. 운영 중인 시스템의 내부 구조를 바꾸면서 화면까지 함께 고치면, 문제가 생겼을 때 원인이 구조 변경인지 화면 수정인지 가려내기 어렵습니다.
8. 도입을 검토할 때 확인할 것
비슷한 시스템을 검토하고 계시다면, 공급사에 다음 질문을 해 보시기를 권합니다. 답이 구체적일수록 운영 단계를 고려해 만든 시스템입니다.
- 기기 상태는 주기 조회입니까, 변화가 생길 때 받습니까
- 현장 인터넷이 끊겼다가 복구되면 화면은 어떻게 다시 맞춰집니까
- 제어 명령을 보낸 뒤 실제로 반영되었는지 확인합니까
- 같은 기기에 명령이 연달아 들어가면 어떻게 처리합니까
- 제어 이력에 수동과 자동, 실행한 규칙이 구분되어 남습니까
- 자동 제어 중에 사람이 직접 조작하면 어떻게 됩니까
- 여러 동작을 묶어 실행하다 일부가 실패하면 어떻게 됩니까
- 전력 사용량은 어떤 단위로, 어디에서 가져옵니까
- 도입 이전 기간의 사용량을 넣을 수 있습니까
- 계정이 없는 이용자는 어떤 방법으로, 어디까지 조작할 수 있습니까
마치며
공간 에너지 관리 시스템에서 화면은 가장 작은 부분입니다. 상태를 놓치지 않고 받는 일, 명령이 실제로 반영되었는지 확인하는 일, 자동화가 사람과 부딪히지 않게 하는 일, 전력 데이터의 빈 구간을 채우는 일이 화면 뒤에 있습니다.
이 네 가지가 갖춰져야 "에어컨을 껐더니 전기요금이 얼마 줄었다"는 문장을 기록으로 말할 수 있습니다. 제어와 계측 중 한쪽만 있으면 절감은 추정에 머무릅니다.
저희는 B-Saver를 직접 개발해 운영하면서 건물·숙박·공유 공간의 기기 제어와 전력 데이터 연동을 다뤄 왔습니다. 기존 설비에 공간 단위 제어를 얹거나 전력 데이터와 연결하는 일을 준비하고 계시다면 편하게 문의해 주세요.
함께 보면 좋은 글
- 건물 전기요금을 줄이는 순서 — 측정 없이 절감은 시작되지 않습니다
- 회의실 에어컨은 왜 계속 켜져 있는가 — 재실 기반 공간 제어 설계
- 현장에 설치된 IoT 시스템을 운영한다는 것 — 단절·상태 불일치·원격 관리

