전기 에너지는 더 이상 무제한적인 자원으로 여겨지지 않습니다. 소비되는 모든 와트는 비용, 효율성, 그리고 많은 경우 안전에 영향을 미칩니다. 스마트 그리드는 복잡한 유행어가 아닙니다. 간단히 말해, 전기 인프라를 지속적으로 모니터링하고, 데이터를 실시간으로 수집하며, 추측이 아닌 측정값을 기반으로 의사 결정을 내리는 것을 의미합니다. 전압, 전류, 전력 및 에너지를 추적하면 부하 균형을 맞추고, 비정상적인 소비를 조기에 감지하며, 장비 손상을 예방할 수 있습니다.
가정에서는 가전제품별 에너지 사용량 추적을 통해 전기 요금을 절감 할 수 있습니다 . 소규모 산업 현장에서는 부하 분석 및 예방 정비를 지원합니다. 연구실과 작업장에서는 설계 검증을 안전하게 수행할 수 있도록 도와줍니다. 로컬 모니터링뿐만 아니라 장기적인 데이터 저장 및 시각화 또한 매우 중요합니다. ThingSpeak 와 같은 클라우드 플랫폼으로 측정값을 전송하면 과거 추세를 기록하고, 그래프를 자동으로 생성하며, 어디서든 원격으로 시스템을 모니터링할 수 있습니다. 이를 통해 모니터링 노드는 단순한 계량기를 넘어 실용적인 IoT 기기로 거듭납니다. 스마트 그리드가 IoT에서 얼마나 중요한지는 그 활용 범위가 얼마나 넓은지를 고려할 때 명확해집니다. 가정에서는 가전제품별 에너지 사용량 추적을 통해 전기 요금을 절감할 수 있습니다.

이 IoT 스마트 에너지 그리드 프로젝트는 Arduino UNO R4 WiFi 와 PZEM 004T 에너지 미터를 사용하여 간단하지만 실용적인 스마트 그리드 모니터링 노드를 구축하는 과정을 안내합니다 . 목표는 복잡성이 아닌 명확성과 신뢰성입니다. 이 시스템은 전기 매개변수를 측정하여 OLED 화면에 표시하고, 원격 모니터링 및 분석을 위해 데이터를 클라우드에 업로드합니다. 더 많은 Arduino 기반 프로젝트에 관심이 있으시면 저희 Arduino 프로젝트 모음을 확인해 보세요 .
목차
사물인터넷(IoT)에서 스마트 그리드란 무엇일까요?
PZEM 004T 에너지 미터 이해하기
필수 구성 요소
회로도
└ 배선 연결
작동 원리
아두이노 라이브러리 연동 - PZEM004Tv40_R4
소스 코드 설명
실제 배포
└ 하드웨어 설정
클라우드 대시보드 출력
└ 3D 프린팅 케이스
문제 해결
GitHub 저장소
사물인터넷(IoT)에서 스마트 그리드란 무엇일까요?
IoT 스마트 그리드는 센서, 마이크로컨트롤러, 클라우드 기반 분석 기능을 통합한 전력 배분 네트워크입니다. 스마트 그리드 장치들은 중앙 컴퓨팅 시스템과 유선 및 무선 통신을 통해 전압, 전류, 주파수, 역률을 매초 측정합니다. 이를 통해 운영자는 24시간 내내 전력 흐름을 모니터링하고, 비정상적인 작동 조건에 대한 경고를 받고, 소비자의 사용 이력을 기반으로 전력 배분 패턴을 조정하고, 과거 사용 추세에 대한 보고서를 생성할 수 있습니다.
| Parameter | Unit | What It Indicates | Typical Single-Phase Range |
| Voltage | V | Supply quality and stability | 220–240 V (IN/EU) | 110–120 V (US) |
| Current | A | Load demand and wire thermal stress | 0–100 A (PZEM-004T range) |
| Real Power | W | Actual useful work performed | 0–23,000 W |
| Energy | kWh | Accumulated electricity consumed | 0–9999.99 kWh |
| Frequency | Hz | Grid stability | 45–65 Hz |
| Power Factor | PF | Efficiency of current conversion to work | 0.00–1.00 |
사물인터넷(IoT)에서 스마트 그리드의 중요성
스마트 그리드는 기존 전력 배전 시스템에 비해 에너지 절약, 장비 보호, 운영 효율성이라는 세 가지 주요 이점을 제공합니다. 사물 인터넷(IoT) 환경에서 스마트 그리드의 중요성은 에너지 효율성, 장비 안전, 운영 지능화에까지 미칩니다.
기존의 전기 계량기는 월말 총 사용량만 보여줍니다. 반면 사물 인터넷(IoT) 기반의 스마트 그리드는 실시간(초 단위)으로 세부적인 데이터를 제공하여, 기존에는 파악하기 어려웠던 소비 추세를 보여줄 뿐만 아니라, 고장으로 인해 과도한 전류를 소모하는 가전제품을 식별하고, 전압 강하나 급증으로 인해 연결된 기기가 손상될 가능성도 알려줍니다. 인도처럼 전력망 전압 변동이 심하고 동일 위치에서도 공급 전압이 180V에서 250V까지 오르내리는 국가에서는 실시간 전압 모니터링을 통해 장비 손상을 최소화할 수 있으며, 이는 모니터링 시스템 구축 비용을 훨씬 초과하는 경우가 많습니다.
산업 부문에서 얻는 추가적인 절감 효과는 주거용 고객보다 훨씬 큽니다. 역률을 지속적으로 측정할 수 있기 때문에 산업체는 비효율적으로 작동하는 특정 모터나 콘덴서 뱅크를 식별할 수 있으며, 이는 전력 회사가 부과하는 낮은 역률(PF)에 대한 벌금을 줄이는 데 도움이 됩니다. 또한 실시간 부하 데이터를 활용하여 수요 측 관리가 가능해지므로 부하 차단 및 피크 수요 계획을 수립할 수 있습니다. 태양광 에너지 사용자의 경우, IoT 기반 스마트 그리드를 통해 실시간으로 발전량과 소비량을 모니터링할 수 있어 발전과 소비의 균형을 맞출 수 있습니다. 이러한 개선 사항은 측정 및 금전적 측면에서 정량화할 수 있으며, 이 프로젝트의 모든 구성 요소와 관련된 비용을 정당화합니다.
전력망의 기본 원리
하드웨어를 연결하기 전에 측정 대상이 무엇인지 이해하는 것이 중요합니다. 대부분의 가정용 및 소규모 상업용 시스템은 단상 교류 전원을 사용합니다. 주 전압은 50Hz 또는 60Hz의 정현파로 교류합니다. 이러한 교류 특성으로 인해 크기와 위상 모두 중요합니다. 전압은 전기적 전위차를 나타냅니다. 부하를 통해 전류를 밀어내는 압력으로 시각화할 수 있습니다. 전압이 너무 높아지면 장치가 고장날 수 있습니다. 전압이 너무 낮아지면 모터가 과열되고 전자 장치가 예측할 수 없는 방식으로 작동합니다. 전류는 전하의 실제 흐름을 나타냅니다. 전류가 높을수록 전선과 부품에 더 많은 부하가 걸립니다. 과전류는 과열 및 화재 위험의 주요 원인입니다.
전력은 에너지가 소비되는 속도를 나타냅니다. 와트(W) 로 측정되는 실효 전력 은 실제로 유용한 일을 하는 데 사용되는 전력입니다. 이는 전기 요금 고지서에 표시되는 값입니다. 에너지는 시간에 걸쳐 누적된 전력이며 킬로와트시(kWh)로 측정됩니다. 이 값은 실제로 얼마나 많은 전기가 사용되었는지에 대한 답을 제공합니다. 주파수는 전력망의 안정성을 나타냅니다. 공칭 주파수에서 크게 벗어나는 것은 시스템에 과부하가 걸리거나 불균형이 발생했음을 의미할 수 있습니다. 역률은 전류가 유용한 일로 얼마나 효율적으로 변환되는지를 나타냅니다. 역률이 낮으면 용량 낭비와 손실 증가로 이어집니다. 이러한 매개변수를 모니터링하면 전력망의 상태를 종합적으로 파악할 수 있습니다.
PZEM 004T 에너지 미터 이해하기

IoT 기반 스마트 그리드 모니터링 시스템에 사용되는 PZEM-004T 에너지 미터 모듈
PZEM 004T 는 임베디드 애플리케이션용으로 설계된 소형 디지털 에너지 미터 모듈입니다. 전압 감지, 전류 측정 및 내부 신호 처리가 하나의 보드에 통합되어 있습니다. 전압은 AC 라인에 연결된 내부 저항 분배기를 사용하여 측정합니다. 전류는 외부 전류 변압기를 통해 측정합니다. 이 변압기는 단일 도체를 감싸고 자속을 감지하여 절연을 제공하고 안전성을 향상시킵니다. 모든 측정 관련 복잡한 기능이 PZEM 모듈 내부에 통합되어 있어 IoT 기반 스마트 그리드 시스템의 개발 시간과 펌웨어 복잡성을 크게 줄여줍니다.
모듈 내부에는 에너지 측정 IC가 내장되어 전압 및 전류 파형을 샘플링하고, 실효값(RMS)을 계산하고, 유효 전력을 산출하고, 에너지를 적분하고, 주파수와 역률을 측정합니다. 통신은 UART를 통한 Modbus RTU를 사용하여 이루어집니다 . 이는 매우 중요한 특징입니다. 마이크로컨트롤러는 아날로그 신호 처리나 교정 작업 대신 요청 프레임을 전송하고 측정값을 디지털 방식으로 수신하기만 하면 됩니다. 복잡한 과정이 추상화되어 있기 때문입니다. 임베디드 시스템 개발 시 이러한 방식은 설계 시간을 크게 단축시켜 줍니다. 이 모듈은 인도/유럽의 230V 회로와 북미의 120V 전원 공급 장치를 모두 지원하므로 스마트 그리드 IoT 시스템의 전 세계적인 구축에 적합합니다.
| Specification | Value |
| Voltage measurement range | 80 – 260 V AC |
| Current measurement range | 0 – 100 A AC (via CT clamp) |
| Active power range | 0 – 23,000 W |
| Energy accumulation | 0 – 9999.99 kWh |
| Frequency range | 45 – 65 Hz |
| Power factor range | 0.00 – 1.00 |
| Communication protocol | Modbus RTU over UART, 9600 baud, 8N1 |
| Logic supply voltage | 5 V DC |
| Voltage measurement accuracy | plusmn;0.5% |
| Current measurement accuracy | plusmn;0.5% |
사물인터넷 기반 스마트 그리드 모니터링 시스템 구축
PZEM 004T가 전기적 매개변수를 측정하는 방식을 이해했다면 , 다음 단계는 이를 완전한 IoT 노드에 통합하는 것입니다. 목표는 간단합니다. 데이터를 수집하고, 처리하고, 표시하고, 원격으로 접근할 수 있도록 하는 것입니다. 전압 감지를 위해 전원 라인은 PZEM에 연결되고, 전류 변압기는 활선 도체에 고정됩니다. 모듈은 내부적으로 실효 전압, 전류, 전력, 에너지, 주파수 및 역률을 계산합니다. 컨트롤러 레벨에서 복잡한 아날로그 설계나 교정은 필요하지 않습니다.
이 값들은 Modbus RTU를 사용하는 UART를 통해 Arduino UNO R4 WiFi 에서 디지털 방식으로 읽어옵니다 . 이를 통해 신호 처리에서 깔끔한 데이터 처리로 문제가 전환되어 펌웨어 설계가 간소화되고 신뢰성이 향상됩니다. 수신된 데이터는 즉시 확인할 수 있도록 로컬 OLED 디스플레이 에 표시됩니다 . 동시에 측정값은 WiFi를 통해 ThingSpeak로 전송되어 로깅 및 시각화됩니다. 이를 통해 현장 모니터링과 원격 액세스가 모두 가능합니다. 결과적으로, 로컬에서 감지하고 중앙에서 보고하는 소형 엣지 디바이스가 구현됩니다. 이 아키텍처는 모듈식으로 설계되어 디버깅이 용이하고, 향후 추가 측정 장치나 분석 기능을 쉽게 확장할 수 있습니다.
사물인터넷(IoT) 기반 스마트 그리드 구축에 필요한 구성 요소
아래 이미지는 IoT를 활용한 스마트 그리드 모니터링 시스템 제작에 사용된 구성 요소들의 시각적 이미지를 보여줍니다.

IoT 기반 스마트 그리드 시스템의 모든 구성 요소: 아두이노 UNO R4 WiFi, PZEM-004T 에너지 미터, CT 클램프, OLED 디스플레이 및 푸시 버튼
이 표는 회로 구성 요소 목록과 회로에서의 용도를 보여줍니다.
| 요소 | 수량 | 메모 |
| 아두이노 UNO R4 WiFi | 1 | Wi-Fi 및 Modbus 통신용 하드웨어 시리얼 포트가 내장된 메인 컨트롤러 |
| PZEM 004T 에너지 미터 | 1 | 전압, 전류, 전력, 에너지, 주파수 및 역률을 측정합니다. |
| 전류 변압기 코일 | 1 | PZEM이 탑재되어 있어 직접 접촉 없이 안전하게 부하 전류를 감지합니다. |
| OLED 디스플레이 | 1 | 실시간 측정값 및 시스템 상태를 표시하는 로컬 디스플레이 |
| 버튼을 누르세요 | 1 | 화면 모드를 전환하거나 롤링 스크린을 활성화하는 데 사용됩니다. |
| 브레드보드 또는 PCB | 1 | 연결부 조립 및 테스트용 |
| 점퍼 와이어 | 여러 개의 | 신호 및 전원 배선을 위한 수-수 및 수-암 케이블 |
| USB 케이블 | 1 | 아두이노 보드 프로그래밍 및 전원 공급 |
| AC 부하 | 1 | 측정값 검증을 위한 시험 부하 |
스마트 그리드 IoT 시스템의 시스템 아키텍처
아래 IoT 다이어그램의 스마트 그리드를 참조하면, 이 시스템은 3계층 엣지-클라우드 아키텍처를 따릅니다. 각 계층을 이해하면 문제 해결 및 향후 확장이 용이해집니다. 시스템은 세 가지 주요 블록을 중심으로 구축된 간단한 엣지-클라우드 아키텍처를 따릅니다. 전기 매개변수는 먼저 PZEM 004T 에서 수집됩니다. 이 모듈 은 주전압을 직접 감지하고 전류 변압기를 사용하여 부하 전류를 안전하게 측정합니다. 모듈은 이러한 신호를 내부적으로 처리하여 전압, 전류, 전력, 에너지, 주파수 및 역률과 같은 유용한 값을 계산합니다. 이러한 측정값은 Modbus RTU를 통해 UART를 거쳐 Arduino UNO R4 WiFi로 디지털 방식으로 전송됩니다. 컨트롤러는 시스템의 핵심 역할을 합니다. 주기적으로 미터를 폴링하고, 최신 측정값을 저장하고, 데이터를 포맷하고, 프로세서를 차단하지 않고 타이밍을 관리하여 감지, 디스플레이 업데이트 및 통신이 원활하게 이루어지도록 합니다.
처리 후 데이터는 두 개의 출력으로 전달됩니다. OLED 디스플레이는 즉각적인 현장 피드백을 제공하여 노트북 없이도 기기에서 직접 측정값을 확인할 수 있도록 합니다. 동시에 내장 Wi-Fi는 측정값을 주기적으로 ThingSpeak 에 업로드하여 원격 로깅 및 시각화를 지원합니다. 이를 통해 실시간 모니터링과 장기적인 이력 추적이 모두 가능합니다. 간단히 말해, PZEM은 측정을 담당하고, Arduino는 로직 및 통신을 담당하며, 클라우드는 저장 및 분석을 담당합니다. 결과적으로, 단순한 계량기가 아닌 소형 스마트 그리드 엔드포인트처럼 작동하는 컴팩트하고 안정적인 모니터링 노드가 탄생합니다.
사물인터넷(IoT) 기반 스마트 그리드의 회로도
아래 이미지는 아두이노 UNO R4 WiFi, PZEM-004T 에너지 미터, OLED 디스플레이 및 푸시 버튼 간의 모든 배선을 포함한 전체 스마트 그리드 IoT 회로도를 보여줍니다.

사물인터넷(IoT) 기반 스마트 그리드의 회로도
| 신호 | PZEM-004T 핀 | 아두이노 UNO R4 WiFi 핀 |
| Modbus TX (직렬 데이터 출력) | 텍사스 | Serial1 RX — 핀 0 |
| Modbus RX (직렬 데이터 입력) | RX | Serial1 TX — 핀 1 |
| 논리력 | 5볼트 | 5볼트 |
| 공통점 | 접지 | 접지 |
| OLED I2C 데이터 | — | A4 (SDA) |
| OLED I2C 클럭 | — | A5 (SCL) |
| 버튼을 누르세요 | — | 디지털 핀 7 (INPUT_PULLUP) |
스마트 그리드 모니터링 시스템의 작동 원리
시스템 전원이 켜지면 Arduino UNO R4 WiFi는 시리얼 포트, OLED 디스플레이, WiFi 인터페이스 및 PZEM 004T 를 초기화합니다 . PZEM은 AC 라인을 지속적으로 감지합니다. 전압은 주 전원 단자에서 직접 측정하고 전류는 연결된 전류 변압기를 통해 측정합니다. 모듈 내부에서 이러한 신호는 샘플링 및 처리되어 실효 전압, 실효 전류, 유효 전력, 누적 에너지, 주파수 및 역률을 계산합니다. 모듈은 아날로그 신호를 그대로 전송하는 대신 이러한 값을 디지털 방식으로 저장하고 Arduino의 Modbus 요청을 기다립니다. 이러한 지속적인 감지-처리-표시-업로드 과정이 스마트 그리드 IoT 모니터링 노드의 전체 작동 주기를 구성합니다.
아두이노는 일정한 시간 간격으로 UART를 통해 Modbus 쿼리를 전송하고 최신 측정값을 수신합니다. 펌웨어는 응답을 확인하고 각 매개변수를 추출하여 내부 변수를 업데이트합니다. 이러한 값은 로컬 모니터링을 위해 OLED 디스플레이에 즉시 표시되고 디버깅을 위해 시리얼 콘솔에도 출력됩니다. Wi-Fi 연결이 가능한 경우 동일한 데이터가 ThingSpeak로 전송되어 기록되고 원격 접속을 위해 그래프로 표시됩니다. 이 과정은 지속적으로 반복되어 감지, 처리, 표시 및 업로드의 실시간 루프를 형성하며, 이는 스마트 그리드 모니터링 시스템의 핵심 작동 방식입니다. 더 많은 스마트 에너지 시스템을 구축하고 싶으신가요? ESP12와 아두이노를 사용한 전력 모니터링 프로젝트도 확인해 보세요.
아두이노 라이브러리 연동 - PZEM004Tv40_R4
이 시스템은 전용 Arduino 라이브러리를 사용하여 PZEM 004T와 통신합니다. 이 라이브러리를 사용하면 Modbus RTU 프레임을 수동으로 생성하거나, CRC 검사를 계산하거나, 레지스터를 분석할 필요가 없습니다. 펌웨어는 필요한 값만 요청하면 되고, 라이브러리는 패킷을 구성하고 전송하고, 응답을 검증하고, 데이터를 자동으로 추출합니다. 덕분에 코드가 깔끔하고 읽기 쉬우며, 수동 Modbus 구현에서 흔히 발생하는 통신 오류를 줄일 수 있습니다.
CircuitDigest 엔지니어링 팀의 전문가 가이드 - 하드웨어 Serial1 인터페이스를 활용하는 Arduino UNO R4 WiFi. 이 방식은 표준 구현에서 발생하는 타이밍 불일치를 방지하며, Arduino 라이브러리 관리자, PlatformIO 또는 GitHub를 통해 이용할 수 있습니다.
코드에서 통합은 간단하고 직접적으로 이루어집니다. 프로그램은 하드웨어 직렬 포트를 사용하여 PZEM 객체를 생성하고, setup 함수에서 모듈을 한 번 초기화한 후, 단일 함수 호출로 모든 매개변수를 읽습니다. 그런 다음 명확한 getter 함수를 사용하여 전압, 전류, 전력, 에너지, 주파수 및 역률을 가져옵니다. 이러한 설계 덕분에 펌웨어는 하위 수준의 통신 세부 사항을 처리하는 대신 디스플레이 업데이트 및 클라우드로 데이터 업로드와 같은 작업에 집중할 수 있습니다.
ThingSpeak 클라우드 계정 설정하기
» 이메일을 사용하여 무료 ThingSpeak 계정을 만들고 대시보드에 로그인하세요.
» 로그인 후, '새 채널'을 클릭합니다 . 채널은 모든 에너지 측정값을 저장하고 그래프로 표시하는 컨테이너 역할을 합니다.
» 채널 설정에서 여러 필드를 활성화하고 전압, 전류, 전력, 에너지, 주파수, 역률 과 같이 명확하게 이름을 지정하세요 .
» 적절한 이름 지정은 대시보드를 읽기 쉽게 하고 나중에 혼동을 방지합니다.
» 다음으로, 'API 키' 탭을 엽니다. 채널 ID와 API 키를 복사합니다. 이 두 값을 통해 Arduino는 데이터를 클라우드로 안전하게 전송할 수 있습니다.
» 이 값을 코드에 붙여넣습니다. 펌웨어를 업로드하면 보드가 자동으로 측정값을 전송하기 시작하고 대시보드에 실시간으로 그래프가 표시됩니다. 이로써 클라우드 통합이 완료되어 모든 장치에서 원격으로 모니터링할 수 있습니다.
소스 코드 설명
다음 섹션에서는 펌웨어의 각 구성 요소에 대해 설명합니다. 설명은 에너지 미터에서 시작하여 컨트롤러를 거쳐 최종적으로 디스플레이 및 클라우드 플랫폼에 도달하는 주요 데이터 흐름에 중점을 둡니다. 전체적인 논리를 명확하고 간결하게 이해하기 쉽도록 하기 위해 부가적인 설정 세부 정보 및 간단한 보조 루틴은 의도적으로 생략했습니다.
객체 초기화
PZEM004Tv40_R4 pzem(&Serial1);
WiFiClient client;
PZEM 객체 는 하드웨어 Serial1 포트에 연결되어 에너지 미터와의 Modbus 통신을 처리합니다. 이를 통해 센서 데이터 트래픽을 USB 디버그 시리얼과 분리하여 충돌을 방지하고, WiFi 클라이언트는 측정값을 클라우드에 업로드하는 데 필요한 모든 네트워크 통신을 관리합니다.
논블로킹 타이머
unsigned long lastReadTime = 0;
const unsigned long readInterval = 1000;
이 변수들은 millis를 사용하여 비차단 타이밍을 구현하므로 프로그램이 지연에 의존하는 대신 경과 시간을 확인할 수 있어 시스템 응답성을 유지하고 센서 판독, 디스플레이 업데이트 및 WiFi 통신이 동시에 원활하게 실행될 수 있도록 합니다.
주기적 센서 판독 트리거
if (currentMillis - lastReadTime >= readInterval) {
lastReadTime = currentMillis;
readPZEMData();
}
이 블록은 시간 간격을 확인하여 주기적인 센서 판독을 예약하고, 메인 루프를 일시 중지하지 않고 매초 한 번씩 트리거하여 일관된 샘플링을 유지하는 동시에 다른 작업이 병렬로 계속 실행될 수 있도록 합니다.
6가지 매개변수 모두 읽기
if (pzem.readAll()) {
voltage = pzem.getVoltage();
current = pzem.getCurrent() * 1000;
}
이 라이브러리는 모든 측정값을 단일 Modbus 트랜잭션으로 읽어들이고, 나중에 사용할 수 있도록 값을 간단한 변수에 저장하며, 단위 변환을 즉시 수행하여 나머지 코드가 명확하고 사람이 읽기 쉬운 숫자로 작동하도록 합니다.
화면 업데이트 및 클라우드 업로드
updateDisplay();
uploadToThingSpeak();
한 기능은 로컬 시각화를 관리하고 다른 기능은 클라우드 로깅을 관리하여 책임을 명확하게 분리하고, 표시 로직과 네트워킹 작업을 혼합하는 것을 방지하며, 각 블록을 독립적으로 테스트할 수 있으므로 디버깅을 간소화합니다.
ThingSpeak 필드 할당 및 업로드
ThingSpeak.setField(1, voltage);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
측정값은 먼저 해당 클라우드 필드에 할당된 다음, 단일 API 호출을 통해 모든 매개변수가 ThingSpeak로 전송됩니다. 그러면 플랫폼이 자동으로 데이터를 저장하고 시각화를 위한 그래프를 생성합니다.
실제 배포
하드웨어 설정
이 하드웨어는 아두이노 UNO R4 WiFi, PZEM 004T, 전류 변환기 및 OLED 디스플레이를 하나의 소형 장치로 연결하여 조립했습니다. PZEM은 전원 라인에서 전압과 전류를 직접 측정하고 UART를 통해 측정값을 아두이노로 전송합니다.
모든 배선이 연결된 아두이노 UNO R4 WiFi, PZEM-004T 에너지 미터 및 OLED 디스플레이를 보여주는 IoT 기반 스마트 그리드 모니터링 하드웨어 조립 모습
아두이노는 이 데이터를 처리하고 OLED 화면에 실시간 값을 표시합니다. 따라서 컴퓨터나 인터넷 연결 없이도 전압, 전류, 전력 및 에너지를 즉시 쉽게 확인할 수 있습니다.
클라우드 대시보드 출력
이 시스템은 동일한 측정값을 WiFi를 통해 정기적으로 ThingSpeak 플랫폼으로 전송합니다. 플랫폼은 데이터를 저장하고 각 매개변수에 대한 그래프를 자동으로 생성합니다. 이러한 차트는 시간 경과에 따른 에너지 사용량을 추적하고 변화 또는 비정상적인 동작을 쉽게 파악하는 데 도움이 됩니다. 이는 이 프로젝트가 단순한 로컬 계량기 역할뿐만 아니라 원격 모니터링 솔루션으로서도 작동함을 입증합니다.

ThingSpeak 클라우드 대시보드는 Arduino 스마트 그리드 IoT 시스템의 전압, 전류, 전력, 에너지, 주파수 및 역률에 대한 실시간 그래프를 보여줍니다.
3D 프린팅 케이스

스마트 그리드 IoT 프로젝트용 맞춤형 3D 프린팅 케이스로, 아두이노 UNO R4 WiFi 및 PZEM-004T를 수납하며 OLED 디스플레이와 푸시 버튼용 구멍이 있습니다.
모든 전자 부품을 안전하게 수납할 수 있도록 맞춤형 케이스를 설계하고 3D 프린팅했습니다 . 아두이노 UNO R4 WiFi, PZEM 004T, 그리고 배선을 케이스 안에 안전하게 고정하고, OLED 디스플레이, 버튼, 케이블을 위한 적절한 구멍을 뚫었습니다. 덕분에 내부가 깔끔하게 정리되고 부품들이 보호되며, 실용적인 용도에 적합한 깔끔하고 전문적인 마감을 갖추게 되었습니다. 또한 에너지 미터 관련 흥미로운 프로젝트도 진행했습니다. 전압 초과, 과전류 등의 조건이 충족되면 시스템에서 사용자에게 SMS 알림을 보내도록 설계했으니, 저희의 IoT 기반 스마트 에너지 미터(SMS 알림 기능 포함) 도 한번 살펴보시기 바랍니다 .
스마트 그리드 IoT 애플리케이션
이 프로젝트와 스마트 그리드 사물 인터넷 (IoT)이 현재 어떻게 활용되고 있는지 더 자세히 이해하기 위해 IoT 생태계 전체를 살펴보겠습니다. 이 튜토리얼에서는 개발 중인 모델이 단일 노드 시스템으로 구성되어 있음을 보여드리지만, 동일한 설계 모델과 펌웨어를 사용하여 실제 환경에서 여러 인스턴스로 확장할 수 있습니다.
* 가정용 에너지 관리 시스템(HEMS): 주택 소유자가 각 가전제품의 에너지 사용량을 모니터링하고, 대기 전력을 감지하며, 사용량 스케줄링을 자동화하여 피크 수요 요금을 절감할 수 있도록 지원합니다.
* 산업 부하 모니터링. 제조업체는 과전류, 역률 저하, 예기치 않은 전력 급증과 같은 상황으로 인한 잠재적 고장 징후를 파악하기 위해 생산 설비의 에너지 소비량을 모니터링할 수 있습니다.
* 태양광 및 기타 재생에너지 시스템. 해당 자원의 발전량을 실시간으로 모니터링하고 전력망의 에너지 소비량과 비교하여 배터리 충전/방전 최적 방법을 결정하고 잉여 발전량을 전력망으로 송전할 시기를 결정할 수 있습니다.
* 유틸리티용 스마트 계량: 전력 계량기 показания를 자동으로 수집하여 유틸리티 회사가 수동으로 계량기를 검침하고 요금을 대조할 필요성을 없애줍니다.
* 전기차(EV) 충전소 모니터링: 사용자에게 정확한 요금을 청구하고 전력망에 미치는 영향을 평가하는 데 사용할 수 있는 검증되고 완전한 EV 충전 데이터를 제공합니다.
* 실험실 및 작업장 안전: 시험 교란 시험대에서 과부하에 대한 부하 조건을 모니터링하면 민감한 장비의 손상을 방지하고 상류 회로 차단기가 트립되는 것을 방지하는 데 도움이 됩니다.
* 농업용 펌핑 시스템: 모터의 에너지 소비량을 모니터링하고 관련 전류 감소를 통해 공회전 상태를 감지하여 모터의 조기 고장을 방지하는 데 도움이 될 수 있습니다.
* 데이터센터 전력 관리: 데이터센터의 랙 단위에서 전력을 모니터링함으로써 전력 사용 효율을 계산할 수 있습니다.
스마트 그리드 IoT 시스템 문제 해결
| 문제 또는 오류 | 오류 코드 또는 증상 | 의미 | 해결을 위한 조치 |
| 계량기에서 아무런 수치도 나오지 않았습니다. | 응답 없음 | 아두이노가 모드버스 데이터를 수신하지 못하고 있습니다. | TX 및 RX 배선을 점검하고, Serial1 연결을 확인하고, 공통 접지를 확인하십시오. |
| 통신 오류 또는 AC 부하에서 데이터 없음 | 오류 코드 1 | CRC 불일치 또는 프레임 손상 | 전선 길이를 줄이고, 연결부를 단단히 조이고, 주 배선 근처에서 전기적 노이즈가 발생하지 않도록 하십시오. |
| 일정한 0 전류 | 0 A 표시됨 | CT 클램프가 잘못 설치되었습니다. | 활선과 중성선 모두를 클램프하지 말고, 활선 하나만 클램프로 고정하세요. |
| OLED 화면이 표시되지 않음 | 빈 화면 | I2C 통신 문제 | SDA 및 SCL 연결을 확인하고 I2C 주소 0x3C를 확인하십시오. |
| 무작위 재설정 | 보드 재시작 | 불안정한 전원 공급 | 안정적인 5V 어댑터를 사용하고 USB를 통해 과부하 장치에 전원을 공급하지 마십시오. |
스마트 그리드 IoT 애플리케이션의 향후 개선 사항
현재 시스템은 기본적인 실시간 모니터링 및 클라우드 로깅 기능을 제공합니다. 향후 애플리케이션 요구사항에 따라 시스템을 더욱 확장할 수 있습니다. 불필요한 복잡성을 추가하기보다는 안정성과 유용한 기능 구현에 중점을 두어야 합니다.
- 오프라인 데이터 저장을 위해 SD 카드 로깅 기능을 추가합니다.
- 추가 PZEM 모듈을 사용하여 여러 회로를 모니터링하세요.
- 로컬 네트워크 접속을 위한 웹 대시보드를 생성하세요.
- 과전류 또는 과전압 상태에 대한 알림을 추가하세요.
- 비정상적인 측정값에 대한 모바일 알림 기능을 통합하세요.
- 일일 에너지 보고서와 같은 기본적인 분석 작업을 수행합니다.
GitHub 저장소
전체 소스 코드, 배선 세부 정보 및 프로젝트 파일은 참조 및 재사용을 위해 GitHub 저장소에서 확인할 수 있습니다.
IoT GitHub 저장소의 스마트 그리드IoT 스마트 그리드 GitHub 저장소 다운로드
결론
이 프로젝트는 실용적이고 비용 효율적인 부품을 사용하여 아두이노 기반의 완전한 기능을 갖춘 IoT 스마트 그리드 시스템을 구축하는 방법을 보여줍니다. 아두이노 UNO R4 WiFi와 PZEM 004T를 사용하여 실시간으로 전기 매개변수를 측정하고 추적하는 실용적인 스마트 그리드 모니터링 노드를 구축했습니다. 측정값은 로컬 OLED 디스플레이에 표시하고, 동일한 데이터를 ThingSpeak에 업로드하여 원격으로 로깅 및 시각화할 수 있습니다. 전체적인 설계는 단순하고 모듈식이며 유지 관리가 용이하여 학습, 테스트 및 소규모 모니터링 애플리케이션에 적합합니다. 유사한 시스템을 구축하거나 관련 아이디어를 탐구하려는 엔지니어는 이 기반을 확장하고 동일한 개념을 다양한 모니터링 및 IoT 사용 사례에 적용하기 위해 더 많은 PZEM 기반 프로젝트 및 아두이노 기반 프로젝트를 통해 실험을 계속할 수 있습니다. 원격으로 장치를 제어하고 싶으신가요? NodeMCU를 사용한 에너지 미터가 내장된 모바일 작동 홈 자동화 시스템도 확인해 보세요 .
Circuit Digest 엔지니어링 팀 은 모든 IoT 프로젝트를 직접 제작하고 테스트했습니다 . 저희 엔지니어와 기술 문서 작성자들은 메이커, 학생, 전문가들이 쉽게 배울 수 있도록 실용적이고 단계별 튜토리얼을 만드는 데 집중하고 있습니다.
자주 묻는 질문
⇥ PZEM-004T는 전류, 전압 및 역률을 어떻게 측정합니까?
PZEM-004T는 내부 저항 분배기에서 전압을 샘플링하고, AC와 호환되는 분할 코어 전류 변압기를 통해 전류를 측정합니다. PZEM-004T 하드웨어의 일부인 에너지 측정 집적 회로는 실효값(RMS) 방식을 사용하여 RMS 전압과 RMS 전류를 계산하고, 이 값을 이용하여 실효 전력(와트)을 계산합니다(PZEM-004T는 이를 통해 누적 에너지(kWh)를 계산합니다). 또한 주파수(Hz)와 역률을 측정하며, 이러한 값들은 마이크로컨트롤러를 통해 Modbus RTU(9600bps)로 디지털 방식으로 읽어들일 수 있습니다.
⇥ PZEM-004T를 Arduino UNO R4 WiFi에 어떻게 연결하나요?
PZEM-004T의 TX 핀을 Arduino UNO R4 WiFi의 Serial1 RX 핀에, RX 핀을 PZEM-004T의 RX 핀에 연결합니다(교차 연결). PZEM-004T와 Arduino UNO R4 WiFi의 접지는 서로 연결해야 합니다. 또한, PZEM-004T의 두 단자(메인 단자)는 모니터링할 부하에 전원을 공급하는 AC 전원에 연결해야 합니다. CT 코일은 활선에만 감아야 합니다(활선과 중성선 모두에 감지 않도록 주의). 마지막으로, 로컬 디스플레이를 위해 OLED 디스플레이의 SDA와 SCL 단자를 각각 A4와 A5에 연결합니다 .
⇥ 역률이란 무엇이며, 스마트 그리드에서 역률을 모니터링해야 하는 이유는 무엇일까요?
역률은 실효 전력(와트)과 피상 전력(볼트-암페어)의 비율입니다. 역률이 0.9 미만이면 무효 전력 손실이 크고, 전력망 용량이 낭비되며, 전력 회사에서 가정 및 사업장 등 고객 위치까지의 배전 시스템 선로 손실이 크다는 것을 의미합니다. 전력 회사는 공장이나 기타 상업 시설과 같은 산업 현장에서 장기간 낮은 역률을 유지할 경우 추가 요금을 부과합니다. 스마트 그리드 IoT 시스템에서 역률을 모니터링함으로써 전력 회사는 모터, 변압기, 형광등 안정기 등과 같은 비효율적인 유도 부하를 식별하고, 벌금 부과 전에 이를 개선할 수 있습니다.
⇥ 이 IoT 스마트 에너지 그리드 프로젝트는 산업용 또는 3상 애플리케이션에 맞게 확장할 수 있습니까?
네. 여러 개의 PZEM004T를 각각 고유한 Modbus 주소(UART 명령을 통해 주소 지정)에 연결하여 하나의 Arduino(마이크로컨트롤러)로 다양한 회로 또는 기계를 모니터링할 수 있습니다. 3상 애플리케이션의 경우, 각 상에 PZEM-004T 하나씩을 사용하면 완전한 3상 전력 분석이 가능합니다. SD 카드 모듈을 사용하여 로컬 오프라인 로깅을 수행할 수도 있으며, Raspberry Pi 또는 산업용 PC를 사용하여 로컬 SCADA와 유사한 대시보드를 호스팅할 수도 있습니다. 단, 이 경우 핵심 아키텍처에 대한 최소한의 펌웨어 수정이 필요할 수 있습니다.
⇥ 프로젝트에서 측정 데이터를 ThingSpeak에 업로드하는 방법은 무엇인가요?
이 프로젝트는 Wi-Fi를 지원하는 Arduino를 Wi-Fi를 통해 액세스 포인트에 연결하고 ThingSpeak Arduino 라이브러리를 사용하여 15초마다 6개의 측정값(6개 채널로 그룹화됨)을 포함하는 HTTP POST 메시지를 전송함으로써 측정 데이터를 ThingSpeak에 업로드합니다. 측정값은 ThingSpeak.set_field() 문을 사용하여 ThingSpeak 채널에 할당되고, ThingSpeak.write_fields() 호출 한 번으로 6개의 측정값이 모두 전송됩니다. 각 측정값 항목은 ThingSpeak 서버가 데이터를 수신한 시점에 타임스탬프가 기록되며, 6개 채널의 그래프를 실시간으로 업데이트하기 위한 추가 구성은 필요하지 않습니다.
⇥ 스마트 그리드 IoT 기반 프로젝트 구축 시 중요한 안전 예방 조치는 무엇입니까?
PZEM-004T 전원 단자의 배선 변경 또는 연결 작업을 하기 전에 항상 주 전원을 차단하십시오. PZEM-004T 단자에 사용되는 전선을 연결 및 분리할 때는 단자와 커넥터가 견딜 수 있는 최대 전압 및 전류에 적합한 정격의 전선 단자와 커넥터를 사용하십시오. 전류 변환기는 활선에만 연결해야 하며, 활선(전원)과 중성선(중성선) 모두에 연결해서는 안 됩니다. 이렇게 하면 전류 흐름으로 인해 발생하는 자기장이 상쇄되어 전류 측정값이 0으로 표시됩니다. 모든 전원 연결 장치는 비전도성 재질로 만들어진 완전히 밀폐된 케이스에 넣어야 하며, 노출된 테스트 프로브가 있는 활선 AC 회로 단자를 테스트할 때는 항상 주의해야 합니다.
유사한 에너지 모니터링 프로젝트
Arduino, ESP32, 및 STM32를 사용하여 에너지 계량, 실시간 전력 모니터링 및 정밀 전류 감지 문제를 다루는 실습 프로젝트를 살펴보세요.
본 기사의 원문은 이곳을 따라가시면 만나실 수 있습니다. 다른 프로제트도 많습니다.
전체 프로젝트 코드
#include <WiFiS3.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ThingSpeak.h>
#include <PZEM004Tv40_R4.h>
// WiFi credentials
const char* ssid = "Semicon Media";
const char* password = "cracksen1605";
// ThingSpeak settings
unsigned long myChannelNumber = 3238257;
const char* myWriteAPIKey = "CRXGU545EOA6Z8R9";
// OLED Display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
// Button settings
#define BUTTON_PIN 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
PZEM004Tv40_R4 pzem(&Serial1);
WiFiClient client;
// Timing variables (non-blocking)
unsigned long lastReadTime = 0;
unsigned long lastUploadTime = 0;
unsigned long lastSerialPrintTime = 0;
unsigned long lastDisplayUpdateTime = 0;
unsigned long lastDisplaySwitchTime = 0;
unsigned long wifiConnectStartTime = 0;
unsigned long lastButtonPressTime = 0;
const unsigned long readInterval = 1000;
const unsigned long serialPrintInterval = 1000;
const unsigned long displayUpdateInterval = 500;
const unsigned long displaySwitchInterval = 5000;
const unsigned long uploadInterval = 16000;
const unsigned long wifiTimeout = 10000;
const unsigned long debounceDelay = 200;
// Display mode (0 = all parameters, 1-6 = individual parameters)
int displayMode = 0;
// Rolling display control
bool rollingEnabled = false;
bool lastButtonState = HIGH;
bool buttonState = HIGH;
// State machine for WiFi
enum WiFiState {
WIFI_IDLE,
WIFI_CONNECTING,
WIFI_CONNECTED,
WIFI_FAILED
};
WiFiState wifiState = WIFI_IDLE;
// Data storage
float voltage = 0.0;
float current = 0.0;
float power = 0.0;
float energy = 0.0;
float frequency = 0.0;
float powerFactor = 0.0;
bool dataValid = false;
void setup() {
Serial.begin(115200);
Serial.println("PZEM-004T Energy Monitor with ThingSpeak");
Serial.println("==========================================");
// Initialize OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
while (1);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("PZEM Monitor");
display.println("Initializing...");
display.display();
// Initialize button pin with internal pullup
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Initialize PZEM
pzem.begin();
// Initialize ThingSpeak
ThingSpeak.begin(client);
// Start WiFi connection
wifiState = WIFI_CONNECTING;
WiFi.begin(ssid, password);
wifiConnectStartTime = millis();
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
}
void loop() {
unsigned long currentMillis = millis();
// Handle button press
handleButton(currentMillis);
// Handle WiFi state machine
handleWiFi(currentMillis);
// Read PZEM data (non-blocking interval)
if (currentMillis - lastReadTime >= readInterval) {
lastReadTime = currentMillis;
readPZEMData();
}
// Update Serial Monitor (non-blocking interval)
if (currentMillis - lastSerialPrintTime >= serialPrintInterval && dataValid) {
lastSerialPrintTime = currentMillis;
printToSerial();
}
// Switch display mode every 5 seconds (only if rolling is enabled)
if (rollingEnabled && (currentMillis - lastDisplaySwitchTime >= displaySwitchInterval)) {
lastDisplaySwitchTime = currentMillis;
displayMode++;
if (displayMode > 6) {
displayMode = 1; // Reset to first individual parameter (Voltage), skip all-in-one
}
}
// Update OLED Display (non-blocking interval)
if (currentMillis - lastDisplayUpdateTime >= displayUpdateInterval) {
lastDisplayUpdateTime = currentMillis;
updateDisplay();
}
// Upload to ThingSpeak (non-blocking interval)
if (currentMillis - lastUploadTime >= uploadInterval && dataValid) {
if (wifiState == WIFI_CONNECTED) {
lastUploadTime = currentMillis;
uploadToThingSpeak();
}
}
}
void handleWiFi(unsigned long currentMillis) {
switch (wifiState) {
case WIFI_IDLE:
break;
case WIFI_CONNECTING:
if (WiFi.status() == WL_CONNECTED) {
wifiState = WIFI_CONNECTED;
Serial.println("\nWiFi Connected!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
display.clearDisplay();
display.setCursor(0, 0);
display.println("WiFi Connected!");
display.print("IP: ");
display.println(WiFi.localIP());
display.display();
} else if (currentMillis - wifiConnectStartTime >= wifiTimeout) {
wifiState = WIFI_FAILED;
Serial.println("\nWiFi Connection Failed!");
display.clearDisplay();
display.setCursor(0, 0);
display.println("WiFi Failed!");
display.println("Running offline");
display.display();
}
break;
case WIFI_CONNECTED:
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi Disconnected! Reconnecting...");
wifiState = WIFI_CONNECTING;
WiFi.begin(ssid, password);
wifiConnectStartTime = currentMillis;
}
break;
case WIFI_FAILED:
if (currentMillis - wifiConnectStartTime >= 30000) {
Serial.println("Retrying WiFi connection...");
wifiState = WIFI_CONNECTING;
WiFi.begin(ssid, password);
wifiConnectStartTime = currentMillis;
}
break;
}
}
void handleButton(unsigned long currentMillis) {
// Read the button state
int reading = digitalRead(BUTTON_PIN);
// Check if button state has changed and debounce
if (reading != lastButtonState) {
lastButtonPressTime = currentMillis;
}
if ((currentMillis - lastButtonPressTime) > debounceDelay) {
// If the button state has changed
if (reading != buttonState) {
buttonState = reading;
// Button pressed (LOW because of pullup)
if (buttonState == LOW) {
// Toggle rolling mode
rollingEnabled = !rollingEnabled;
if (rollingEnabled) {
Serial.println("Rolling display ON");
displayMode = 1; // Start from first individual parameter (Voltage)
lastDisplaySwitchTime = currentMillis; // Reset timer
} else {
Serial.println("Rolling display OFF");
displayMode = 0; // Go to all-in-one display immediately
}
}
}
}
lastButtonState = reading;
}
void readPZEMData() {
if (pzem.readAll()) {
voltage = pzem.getVoltage();
current = pzem.getCurrent() * 1000;
power = pzem.getPower();
energy = pzem.getEnergy();
frequency = pzem.getFrequency();
powerFactor = pzem.getPowerFactor();
dataValid = true;
} else {
dataValid = false;
Serial.print("Error reading PZEM! Code: ");
Serial.println(pzem.getLastError());
}
}
void printToSerial() {
Serial.print("Voltage: ");
Serial.print(voltage, 1);
Serial.println(" V");
Serial.print("Current: ");
Serial.print(current, 0);
Serial.println(" mA");
Serial.print("Power: ");
Serial.print(power, 1);
Serial.println(" W");
Serial.print("Energy: ");
Serial.print(energy, 3);
Serial.println(" kWh");
Serial.print("Frequency: ");
Serial.print(frequency, 1);
Serial.println(" Hz");
Serial.print("Power Factor: ");
Serial.println(powerFactor, 2);
Serial.println("------------------------");
}
void updateDisplay() {
display.clearDisplay();
if (!dataValid) {
display.setTextSize(1);
display.setCursor(0, 0);
display.println("ERROR!");
display.println("");
display.print("Code: ");
display.println(pzem.getLastError());
display.println("");
display.println("Check connections");
display.display();
return;
}
// Display based on current mode
switch (displayMode) {
case 0:
displayAllParameters();
break;
case 1:
displaySingleParameter("Voltage", voltage, 1, "V");
break;
case 2:
displaySingleParameter("Current", current, 0, "mA");
break;
case 3:
displaySingleParameter("Power", power, 1, "W");
break;
case 4:
displaySingleParameter("Energy", energy, 3, "kWh");
break;
case 5:
displaySingleParameter("Frequency", frequency, 1, "Hz");
break;
case 6:
displaySingleParameter("Power Factor", powerFactor, 2, "");
break;
}
display.display();
}
void displayAllParameters() {
display.setTextSize(1);
// Title
display.setCursor(0, 0);
display.println("Energy Monitor");
display.drawLine(0, 10, 127, 10, SSD1306_WHITE);
// Voltage
display.setCursor(0, 14);
display.print("Voltage : ");
display.print(voltage, 1);
display.println(" V");
// Current (in mA)
display.setCursor(0, 24);
display.print("Current : ");
display.print(current, 0);
display.println(" mA");
// Power
display.setCursor(0, 34);
display.print("Power : ");
display.print(power, 1);
display.println(" W");
// Energy
display.setCursor(0, 44);
display.print("Energy : ");
display.print(energy, 3);
display.println(" kWh");
// Frequency and Power Factor
display.setCursor(0, 54);
display.print("Freq:");
display.print(frequency, 1);
display.print("Hz");
display.setCursor(75, 54);
display.print("PF:");
display.print(powerFactor, 2);
//WiFi status indicator
if (wifiState == WIFI_CONNECTED) {
display.fillRect(118, 6, 2, 2, SSD1306_WHITE);
display.fillRect(121, 4, 2, 4, SSD1306_WHITE);
display.fillRect(124, 2, 2, 6, SSD1306_WHITE);
}
}
void displaySingleParameter(const char* paramName, float value, int decimals, const char* unit) {
// Display parameter name at top
display.setTextSize(1);
display.setCursor(0, 0);
display.println(paramName);
display.drawLine(0, 10, 127, 10, SSD1306_WHITE);
// Display value in large font (size 2)
display.setTextSize(2);
// Convert value to string with proper decimal places
char valueStr[16];
dtostrf(value, 0, decimals, valueStr);
// Calculate position to center the value and unit
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(valueStr, 0, 0, &x1, &y1, &w, &h);
// Position value in the middle of screen
int valueX = (SCREEN_WIDTH - w) / 2;
int valueY = 28;
display.setCursor(valueX, valueY);
display.print(valueStr);
// Display unit in smaller font next to value
if (strlen(unit) > 0) {
display.setTextSize(1);
// Position unit right after the value
display.setCursor(valueX + w + 4, valueY + 8);
display.print(unit);
}
// WiFi status indicator
if (wifiState == WIFI_CONNECTED) {
display.fillRect(118, 6, 2, 2, SSD1306_WHITE);
display.fillRect(121, 4, 2, 4, SSD1306_WHITE);
display.fillRect(124, 2, 2, 6, SSD1306_WHITE);
}
}
void uploadToThingSpeak() {
Serial.println("\nUploading to ThingSpeak...");
// Set the fields
ThingSpeak.setField(1, voltage);
ThingSpeak.setField(2, current);
ThingSpeak.setField(3, power);
ThingSpeak.setField(4, energy);
ThingSpeak.setField(5, frequency);
ThingSpeak.setField(6, powerFactor);
// Write to ThingSpeak channel
int statusCode = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
if (statusCode == 200) {
Serial.println("Channel update successful!");
Serial.print(" Voltage: ");
Serial.print(voltage, 1);
Serial.println(" V");
Serial.print(" Current: ");
Serial.print(current, 0);
Serial.println(" mA");
Serial.print(" Power: ");
Serial.print(power, 1);
Serial.println(" W");
Serial.print(" Energy: ");
Serial.print(energy, 3);
Serial.println(" kWh");
Serial.print(" Frequency: ");
Serial.print(frequency, 1);
Serial.println(" Hz");
Serial.print(" Power Factor: ");
Serial.println(powerFactor, 2);
} else {
Serial.print("Problem updating channel. HTTP error code: ");
Serial.println(statusCode);
}
Serial.println();
}
'아두이노우노 R4' 카테고리의 다른 글
| DIY 아두이노 휴대용 게임 콘솔 (레트로 게임 10개 포함) (0) | 2026.03.25 |
|---|---|
| 아두이노 나노 매터 보드는 전문가용 제피어 개발 플랫폼이 되었습니다. (0) | 2026.03.17 |
| Magnetometer 자력계를 설정하는 방법 - 나침반, 풍향계 적용 (1) | 2026.03.09 |
| 아두이노와 ADXL345 가속도계 방향 추적 3D 시각 (0) | 2026.02.17 |
| 아두이노 IDE에서 ATtiny85 프로그래밍 마스터 1 (1) | 2026.02.16 |
| LDR 및 서보 모터를 사용한 2축 태양광 추적기 아두이노 프로젝트 (0) | 2026.02.14 |
| 아두이노 OLED 메뉴 디스플레이 (2) | 2026.02.03 |
| 아두이노와 3-디스플레이 OLED 시계 (0) | 2026.02.03 |
취업, 창업의 막막함, 외주 관리, 제품 부재!
당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약,
아이디어는 있지만 구현할 기술이 없는 막막함.
우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.
이제 고민을 멈추고, 캐어랩을 만나세요!
코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.
제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!
귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.
캐어랩