<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>https://devcafe.co.kr/w/index.php?action=history&amp;feed=atom&amp;title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</id>
	<title>라즈베리파이 제로 e-ink 사용하기 - 편집 역사</title>
	<link rel="self" type="application/atom+xml" href="https://devcafe.co.kr/w/index.php?action=history&amp;feed=atom&amp;title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0"/>
	<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;action=history"/>
	<updated>2026-05-17T10:42:52Z</updated>
	<subtitle>이 문서의 편집 역사</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2397&amp;oldid=prev</id>
		<title>2026년 5월 6일 (수) 15:21에 Devcafe님의 편집</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2397&amp;oldid=prev"/>
		<updated>2026-05-06T15:21:42Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;amp;diff=2397&amp;amp;oldid=2396&quot;&gt;차이 보기&lt;/a&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2396&amp;oldid=prev</id>
		<title>2026년 5월 6일 (수) 15:13에 Devcafe님의 편집</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2396&amp;oldid=prev"/>
		<updated>2026-05-06T15:13:11Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;amp;diff=2396&amp;amp;oldid=2395&quot;&gt;차이 보기&lt;/a&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2395&amp;oldid=prev</id>
		<title>2026년 5월 6일 (수) 14:21에 Devcafe님의 편집</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2395&amp;oldid=prev"/>
		<updated>2026-05-06T14:21:06Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;amp;diff=2395&amp;amp;oldid=2394&quot;&gt;차이 보기&lt;/a&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2394&amp;oldid=prev</id>
		<title>Devcafe: Devcafe (토론)의 2391 판 편집을 되돌림</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2394&amp;oldid=prev"/>
		<updated>2026-05-06T14:17:29Z</updated>

		<summary type="html">&lt;p&gt;&lt;a href=&quot;/w/%ED%8A%B9%EC%88%98:%EA%B8%B0%EC%97%AC/Devcafe&quot; title=&quot;특수:기여/Devcafe&quot;&gt;Devcafe&lt;/a&gt; (&lt;a href=&quot;/w/index.php?title=%EC%82%AC%EC%9A%A9%EC%9E%90%ED%86%A0%EB%A1%A0:Devcafe&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;사용자토론:Devcafe (없는 문서)&quot;&gt;토론&lt;/a&gt;)의 &lt;a href=&quot;/w/%ED%8A%B9%EC%88%98:%EC%B0%A8%EC%9D%B4/2391&quot; title=&quot;특수:차이/2391&quot;&gt;2391&lt;/a&gt; 판 편집을 되돌림&lt;/p&gt;
&lt;a href=&quot;https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;amp;diff=2394&amp;amp;oldid=2393&quot;&gt;차이 보기&lt;/a&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2393&amp;oldid=prev</id>
		<title>Devcafe: Devcafe (토론)의 2392 판 편집을 되돌림</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2393&amp;oldid=prev"/>
		<updated>2026-05-06T14:17:11Z</updated>

		<summary type="html">&lt;p&gt;&lt;a href=&quot;/w/%ED%8A%B9%EC%88%98:%EA%B8%B0%EC%97%AC/Devcafe&quot; title=&quot;특수:기여/Devcafe&quot;&gt;Devcafe&lt;/a&gt; (&lt;a href=&quot;/w/index.php?title=%EC%82%AC%EC%9A%A9%EC%9E%90%ED%86%A0%EB%A1%A0:Devcafe&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;사용자토론:Devcafe (없는 문서)&quot;&gt;토론&lt;/a&gt;)의 &lt;a href=&quot;/w/%ED%8A%B9%EC%88%98:%EC%B0%A8%EC%9D%B4/2392&quot; title=&quot;특수:차이/2392&quot;&gt;2392&lt;/a&gt; 판 편집을 되돌림&lt;/p&gt;
&lt;a href=&quot;https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;amp;diff=2393&amp;amp;oldid=2392&quot;&gt;차이 보기&lt;/a&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2392&amp;oldid=prev</id>
		<title>Devcafe: /* 라이브러리 설치 */</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2392&amp;oldid=prev"/>
		<updated>2026-05-06T14:15:35Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;라이브러리 설치&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;a href=&quot;https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;amp;diff=2392&amp;amp;oldid=2391&quot;&gt;차이 보기&lt;/a&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2391&amp;oldid=prev</id>
		<title>Devcafe: /* 삼성전자 , 현대차 주가 표시 */</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2391&amp;oldid=prev"/>
		<updated>2026-05-06T14:13:47Z</updated>

		<summary type="html">&lt;p&gt;&lt;span dir=&quot;auto&quot;&gt;&lt;span class=&quot;autocomment&quot;&gt;삼성전자 , 현대차 주가 표시&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;a href=&quot;https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;amp;diff=2391&amp;amp;oldid=2390&quot;&gt;차이 보기&lt;/a&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
	<entry>
		<id>https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2390&amp;oldid=prev</id>
		<title>Devcafe: 새 문서:  ==라즈베리파이 + Waveshare e-Paper로 삼성전자/현대차 실시간 주가 모니터링 == === 개요 === 데이터는 네이버 금융 API(m.stock.naver.com)에서 실시간으로 가져오고, e-ink 수명 보호를 위해 가격이 바뀔 때만 화면을 갱신하도록 구성했습니다.  Waveshare 2.13” 모델 기준이고, 다른 사이즈는 코드 상단에서 모듈만 바꾸면 됩니다.​​​​​​​​​​​​​​​​  === 주요 특징...</title>
		<link rel="alternate" type="text/html" href="https://devcafe.co.kr/w/index.php?title=%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%A0%9C%EB%A1%9C_e-ink_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&amp;diff=2390&amp;oldid=prev"/>
		<updated>2026-05-05T11:28:02Z</updated>

		<summary type="html">&lt;p&gt;새 문서:  ==라즈베리파이 + Waveshare e-Paper로 삼성전자/현대차 실시간 주가 모니터링 == === 개요 === 데이터는 네이버 금융 API(m.stock.naver.com)에서 실시간으로 가져오고, e-ink 수명 보호를 위해 가격이 바뀔 때만 화면을 갱신하도록 구성했습니다.  Waveshare 2.13” 모델 기준이고, 다른 사이즈는 코드 상단에서 모듈만 바꾸면 됩니다.​​​​​​​​​​​​​​​​  === 주요 특징...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;새 문서&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&lt;br /&gt;
==라즈베리파이 + Waveshare e-Paper로 삼성전자/현대차 실시간 주가 모니터링 ==&lt;br /&gt;
=== 개요 ===&lt;br /&gt;
데이터는 네이버 금융 API(m.stock.naver.com)에서 실시간으로 가져오고, e-ink 수명 보호를 위해 가격이 바뀔 때만 화면을 갱신하도록 구성했습니다. &lt;br /&gt;
Waveshare 2.13” 모델 기준이고, 다른 사이즈는 코드 상단에서 모듈만 바꾸면 됩니다.​​​​​​​​​​​​​​​​&lt;br /&gt;
&lt;br /&gt;
=== 주요 특징 ===&lt;br /&gt;
* 주요 특징&lt;br /&gt;
* 데이터 소스: 네이버 모바일 금융 API(m.stock.naver.com/api/stock/{code}/basic) — 별도 API 키 불필요, 응답 안정적&lt;br /&gt;
e-ink 보호 로직:&lt;br /&gt;
	•	가격/등락이 바뀌었을 때만 화면 갱신 (해시 비교)&lt;br /&gt;
	•	장중 1분, 장외 30분 주기로 자동 전환&lt;br /&gt;
	•	SIGTERM/SIGINT 수신 시 화면 클리어 후 sleep 모드 진입&lt;br /&gt;
화면 구성 (2.7” 264x176 가로 모드):&lt;br /&gt;
	•	상단: 현재 시각 + [장중/장외] 표시&lt;br /&gt;
	•	종목별 영역에 종목명, 현재가(큰 글씨), ▲▼ 등락폭/등락률, 시가/고가/저가&lt;br /&gt;
확인이 필요한 부분&lt;br /&gt;
=== 라이브러리 설치 ===&lt;br /&gt;
&lt;br /&gt;
1. 의존 패키지 설치&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
# 시스템 패키지&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install -y python3-pip python3-pil python3-numpy fonts-nanum&lt;br /&gt;
sudo apt install -y python3-spidev python3-rpi.gpio&lt;br /&gt;
&lt;br /&gt;
# 파이썬 패키지&lt;br /&gt;
pip3 install requests Pillow&lt;br /&gt;
&lt;br /&gt;
# SPI 활성화 (raspi-config → Interface Options → SPI → Enable)&lt;br /&gt;
sudo raspi-config&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Waveshare e-Paper 라이브러리 설치&lt;br /&gt;
코드 상단 libdir 경로가 위와 일치하는지 확인.&lt;br /&gt;
다른 모델 사용 시 from waveshare_epd import epd2in7 as epd_module 부분만 변경:&lt;br /&gt;
	•	2.13”: epd2in13_V3&lt;br /&gt;
	•	2.9”:  epd2in9_V2&lt;br /&gt;
	•	4.2”:  epd4in2&lt;br /&gt;
	•	7.5”:  epd7in5_V2&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
cd ~&lt;br /&gt;
git clone https://github.com/waveshare/e-Paper.git&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 실행 테스트&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
python3 stock_monitor.py&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 부팅 시 자동 실행 (systemd)&lt;br /&gt;
/etc/systemd/system/stock-monitor.service 파일 생성:&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Stock Price e-Paper Monitor&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
User=pi&lt;br /&gt;
WorkingDirectory=/home/pi/stock_monitor&lt;br /&gt;
ExecStart=/usr/bin/python3 /home/pi/stock_monitor/stock_monitor.py&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=10&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
활성화&lt;br /&gt;
&amp;lt;source lang=bash&amp;gt;&lt;br /&gt;
sudo systemctl daemon-reload&lt;br /&gt;
sudo systemctl enable stock-monitor.service&lt;br /&gt;
sudo systemctl start stock-monitor.service&lt;br /&gt;
sudo systemctl status stock-monitor.service&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
로그확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
journalctl -u stock-monitor.service -f&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 삼성전자 , 현대차 주가 표시 ===&lt;br /&gt;
&amp;lt;source lang=python&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
“””&lt;br /&gt;
삼성전자(005930) / 현대차(005380) 실시간 주가 모니터 + 주봉 차트&lt;br /&gt;
Raspberry Pi + Waveshare 2.13” e-Paper (250x122)&lt;br /&gt;
&lt;br /&gt;
페이지 자동 전환:&lt;br /&gt;
Page 0 - 요약 (양 종목)&lt;br /&gt;
Page 1 - 삼성전자 + 주봉 차트&lt;br /&gt;
Page 2 - 현대차 + 주봉 차트&lt;br /&gt;
&lt;br /&gt;
Author: 치치 (dbaworks)&lt;br /&gt;
“””&lt;br /&gt;
&lt;br /&gt;
import os&lt;br /&gt;
import re&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import logging&lt;br /&gt;
import signal&lt;br /&gt;
import requests&lt;br /&gt;
from datetime import datetime, timedelta, time as dtime&lt;br /&gt;
from PIL import Image, ImageDraw, ImageFont&lt;br /&gt;
&lt;br /&gt;
libdir = os.path.expanduser(’~/e-Paper/RaspberryPi_JetsonNano/python/lib’)&lt;br /&gt;
if os.path.exists(libdir):&lt;br /&gt;
sys.path.append(libdir)&lt;br /&gt;
&lt;br /&gt;
from waveshare_epd import epd2in13_V4 as epd_module   # ← 모델에 맞게 변경&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
# 설정&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
STOCKS = [&lt;br /&gt;
{‘code’: ‘005930’, ‘name’: ‘삼성전자’},&lt;br /&gt;
{‘code’: ‘005380’, ‘name’: ‘현대차’},&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
CHART_WEEKS = 26                  # 주봉 표시 기간&lt;br /&gt;
DATA_REFRESH_OPEN  = 60           # 장중 시세 갱신 주기 (초)&lt;br /&gt;
DATA_REFRESH_CLOSE = 60 * 30      # 장외 시세 갱신 주기&lt;br /&gt;
CHART_CACHE_TTL    = 60 * 60      # 주봉 캐시 유지 시간 (1시간)&lt;br /&gt;
PAGE_DURATION      = 20           # 페이지 자동 전환 주기 (초)&lt;br /&gt;
FULL_REFRESH_EVERY = 30           # 부분 갱신 N회마다 전체 갱신&lt;br /&gt;
&lt;br /&gt;
FONT_REGULAR = ‘/usr/share/fonts/truetype/nanum/NanumGothic.ttf’&lt;br /&gt;
FONT_BOLD    = ‘/usr/share/fonts/truetype/nanum/NanumGothicBold.ttf’&lt;br /&gt;
&lt;br /&gt;
MARKET_OPEN  = dtime(9, 0)&lt;br /&gt;
MARKET_CLOSE = dtime(15, 30)&lt;br /&gt;
&lt;br /&gt;
logging.basicConfig(&lt;br /&gt;
level=logging.INFO,&lt;br /&gt;
format=’%(asctime)s [%(levelname)s] %(message)s’&lt;br /&gt;
)&lt;br /&gt;
log = logging.getLogger(**name**)&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
# 데이터 조회&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
def fetch_stock(code):&lt;br /&gt;
“”“현재가 (네이버 모바일 API)”””&lt;br /&gt;
url = f’https://m.stock.naver.com/api/stock/{code}/basic’&lt;br /&gt;
headers = {&lt;br /&gt;
‘User-Agent’: ‘Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36’,&lt;br /&gt;
‘Referer’: ‘https://m.stock.naver.com/’,&lt;br /&gt;
}&lt;br /&gt;
try:&lt;br /&gt;
r = requests.get(url, headers=headers, timeout=5)&lt;br /&gt;
r.raise_for_status()&lt;br /&gt;
d = r.json()&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
    def to_int(s):&lt;br /&gt;
        return int(str(s).replace(&amp;#039;,&amp;#039;, &amp;#039;&amp;#039;).replace(&amp;#039;+&amp;#039;, &amp;#039;&amp;#039;).replace(&amp;#039;-&amp;#039;, &amp;#039;&amp;#039;)) if s else 0&lt;br /&gt;
&lt;br /&gt;
    change = to_int(d.get(&amp;#039;compareToPreviousClosePrice&amp;#039;, &amp;#039;0&amp;#039;))&lt;br /&gt;
    sign = d.get(&amp;#039;compareToPreviousPrice&amp;#039;, {}).get(&amp;#039;code&amp;#039;, &amp;#039;3&amp;#039;)&lt;br /&gt;
    if sign in (&amp;#039;4&amp;#039;, &amp;#039;5&amp;#039;):&lt;br /&gt;
        change = -abs(change)&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        &amp;#039;name&amp;#039;        : d.get(&amp;#039;stockName&amp;#039;, &amp;#039;&amp;#039;),&lt;br /&gt;
        &amp;#039;price&amp;#039;       : to_int(d.get(&amp;#039;closePrice&amp;#039;, &amp;#039;0&amp;#039;)),&lt;br /&gt;
        &amp;#039;change&amp;#039;      : change,&lt;br /&gt;
        &amp;#039;change_rate&amp;#039; : float(d.get(&amp;#039;fluctuationsRatio&amp;#039;, &amp;#039;0&amp;#039;)),&lt;br /&gt;
        &amp;#039;sign&amp;#039;        : sign,&lt;br /&gt;
        &amp;#039;open&amp;#039;        : to_int(d.get(&amp;#039;openPrice&amp;#039;, &amp;#039;0&amp;#039;)),&lt;br /&gt;
        &amp;#039;high&amp;#039;        : to_int(d.get(&amp;#039;highPrice&amp;#039;, &amp;#039;0&amp;#039;)),&lt;br /&gt;
        &amp;#039;low&amp;#039;         : to_int(d.get(&amp;#039;lowPrice&amp;#039;, &amp;#039;0&amp;#039;)),&lt;br /&gt;
    }&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    log.error(f&amp;quot;[{code}] 시세 조회 실패: {e}&amp;quot;)&lt;br /&gt;
    return None&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
def fetch_weekly_chart(code, weeks=CHART_WEEKS):&lt;br /&gt;
“””&lt;br /&gt;
주봉 종가 리스트 [(YYYYMMDD, close), …]&lt;br /&gt;
네이버 차트 API: 응답이 Python list-literal 형태의 텍스트&lt;br /&gt;
“””&lt;br /&gt;
end = datetime.now()&lt;br /&gt;
# 여유분 포함해서 weeks*7+30일치 요청&lt;br /&gt;
start = end - timedelta(days=weeks * 7 + 30)&lt;br /&gt;
url = (f’https://api.finance.naver.com/siseJson.naver’&lt;br /&gt;
f’?symbol={code}&amp;amp;requestType=1’&lt;br /&gt;
f’&amp;amp;startTime={start.strftime(”%Y%m%d”)}’&lt;br /&gt;
f’&amp;amp;endTime={end.strftime(”%Y%m%d”)}’&lt;br /&gt;
f’&amp;amp;timeframe=week’)&lt;br /&gt;
try:&lt;br /&gt;
r = requests.get(url, headers={‘User-Agent’: ‘Mozilla/5.0’}, timeout=8)&lt;br /&gt;
r.raise_for_status()&lt;br /&gt;
text = r.text.strip()&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
    # 각 [...] 블록 추출 후 파싱&lt;br /&gt;
    rows = re.findall(r&amp;quot;\[([^\[\]]+)\]&amp;quot;, text)&lt;br /&gt;
    data = []&lt;br /&gt;
    for row in rows:&lt;br /&gt;
        parts = [p.strip() for p in row.split(&amp;#039;,&amp;#039;)]&lt;br /&gt;
        if len(parts) &amp;lt; 5:&lt;br /&gt;
            continue&lt;br /&gt;
        date_str = parts[0].strip(&amp;quot;&amp;#039;\&amp;quot; &amp;quot;)&lt;br /&gt;
        if not date_str.isdigit():     # 헤더 행 스킵&lt;br /&gt;
            continue&lt;br /&gt;
        try:&lt;br /&gt;
            close = float(parts[4])&lt;br /&gt;
            data.append((date_str, close))&lt;br /&gt;
        except (ValueError, IndexError):&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
    return data[-weeks:] if len(data) &amp;gt; weeks else data&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    log.error(f&amp;quot;[{code}] 주봉 조회 실패: {e}&amp;quot;)&lt;br /&gt;
    return []&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
# 유틸&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
def fmt_price(p):&lt;br /&gt;
return f”{p:,}”&lt;br /&gt;
&lt;br /&gt;
def fmt_axis(v):&lt;br /&gt;
“”“차트 y축 라벨용 포맷”””&lt;br /&gt;
if v &amp;gt;= 10000:&lt;br /&gt;
return f’{v/10000:.1f}만’&lt;br /&gt;
if v &amp;gt;= 1000:&lt;br /&gt;
return f’{v/1000:.1f}k’&lt;br /&gt;
return f’{int(v)}’&lt;br /&gt;
&lt;br /&gt;
def change_symbol(sign):&lt;br /&gt;
if sign in (‘1’, ‘2’):&lt;br /&gt;
return ‘▲’&lt;br /&gt;
if sign in (‘4’, ‘5’):&lt;br /&gt;
return ‘▼’&lt;br /&gt;
return ‘-’&lt;br /&gt;
&lt;br /&gt;
def is_market_hours():&lt;br /&gt;
now = datetime.now()&lt;br /&gt;
if now.weekday() &amp;gt;= 5:&lt;br /&gt;
return False&lt;br /&gt;
return MARKET_OPEN &amp;lt;= now.time() &amp;lt;= MARKET_CLOSE&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
# 화면 그리기&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
def _new_canvas(epd):&lt;br /&gt;
“”“가로 모드 빈 캔버스 (250x122)”””&lt;br /&gt;
width, height = epd.height, epd.width&lt;br /&gt;
image = Image.new(‘1’, (width, height), 255)&lt;br /&gt;
return image, ImageDraw.Draw(image), width, height&lt;br /&gt;
&lt;br /&gt;
def build_summary_image(epd, stocks_data):&lt;br /&gt;
“”“요약 페이지: 양 종목을 위/아래 분할 표시”””&lt;br /&gt;
image, draw, width, height = _new_canvas(epd)&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
f_hdr   = ImageFont.truetype(FONT_BOLD,    11)&lt;br /&gt;
f_time  = ImageFont.truetype(FONT_REGULAR, 10)&lt;br /&gt;
f_name  = ImageFont.truetype(FONT_BOLD,    13)&lt;br /&gt;
f_price = ImageFont.truetype(FONT_BOLD,    22)&lt;br /&gt;
f_chg   = ImageFont.truetype(FONT_BOLD,    11)&lt;br /&gt;
f_tiny  = ImageFont.truetype(FONT_REGULAR,  9)&lt;br /&gt;
&lt;br /&gt;
market = &amp;#039;장중&amp;#039; if is_market_hours() else &amp;#039;장외&amp;#039;&lt;br /&gt;
draw.text((2, 0), f&amp;#039;주가[{market}]&amp;#039;, font=f_hdr, fill=0)&lt;br /&gt;
now_str = datetime.now().strftime(&amp;#039;%m-%d %H:%M&amp;#039;)&lt;br /&gt;
bbox = draw.textbbox((0, 0), now_str, font=f_time)&lt;br /&gt;
draw.text((width - (bbox[2] - bbox[0]) - 2, 1), now_str, font=f_time, fill=0)&lt;br /&gt;
draw.line([(0, 13), (width, 13)], fill=0, width=1)&lt;br /&gt;
&lt;br /&gt;
section_h = (height - 14) // len(stocks_data)&lt;br /&gt;
y = 15&lt;br /&gt;
&lt;br /&gt;
for i, d in enumerate(stocks_data):&lt;br /&gt;
    if d is None:&lt;br /&gt;
        draw.text((4, y + 18), &amp;#039;데이터 조회 실패&amp;#039;, font=f_name, fill=0)&lt;br /&gt;
        y += section_h&lt;br /&gt;
        continue&lt;br /&gt;
&lt;br /&gt;
    draw.text((3, y + 2), d[&amp;#039;name&amp;#039;], font=f_name, fill=0)&lt;br /&gt;
    price_str = fmt_price(d[&amp;#039;price&amp;#039;])&lt;br /&gt;
    bbox = draw.textbbox((0, 0), price_str, font=f_price)&lt;br /&gt;
    draw.text((width - (bbox[2]-bbox[0]) - 3, y + 1), price_str, font=f_price, fill=0)&lt;br /&gt;
&lt;br /&gt;
    sym = change_symbol(d[&amp;#039;sign&amp;#039;])&lt;br /&gt;
    chg_str = f&amp;quot;{sym} {abs(d[&amp;#039;change&amp;#039;]):,} ({d[&amp;#039;change_rate&amp;#039;]:+.2f}%)&amp;quot;&lt;br /&gt;
    draw.text((3, y + 26), chg_str, font=f_chg, fill=0)&lt;br /&gt;
&lt;br /&gt;
    ohl = f&amp;quot;시{fmt_price(d[&amp;#039;open&amp;#039;])} 고{fmt_price(d[&amp;#039;high&amp;#039;])} 저{fmt_price(d[&amp;#039;low&amp;#039;])}&amp;quot;&lt;br /&gt;
    draw.text((3, y + 41), ohl, font=f_tiny, fill=0)&lt;br /&gt;
&lt;br /&gt;
    y += section_h&lt;br /&gt;
    if i &amp;lt; len(stocks_data) - 1:&lt;br /&gt;
        draw.line([(0, y - 1), (width, y - 1)], fill=0, width=1)&lt;br /&gt;
&lt;br /&gt;
return image&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
def build_chart_image(epd, stock, chart_data):&lt;br /&gt;
“”“차트 페이지: 단일 종목 + 주봉 라인 차트”””&lt;br /&gt;
image, draw, width, height = _new_canvas(epd)&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
f_name  = ImageFont.truetype(FONT_BOLD,    13)&lt;br /&gt;
f_price = ImageFont.truetype(FONT_BOLD,    16)&lt;br /&gt;
f_chg   = ImageFont.truetype(FONT_BOLD,    11)&lt;br /&gt;
f_tiny  = ImageFont.truetype(FONT_REGULAR,  9)&lt;br /&gt;
&lt;br /&gt;
if stock is None:&lt;br /&gt;
    draw.text((60, 50), &amp;#039;데이터 조회 실패&amp;#039;, font=f_name, fill=0)&lt;br /&gt;
    return image&lt;br /&gt;
&lt;br /&gt;
# 헤더: 종목명 + 현재가&lt;br /&gt;
draw.text((3, 0), stock[&amp;#039;name&amp;#039;], font=f_name, fill=0)&lt;br /&gt;
price_str = fmt_price(stock[&amp;#039;price&amp;#039;])&lt;br /&gt;
bbox = draw.textbbox((0, 0), price_str, font=f_price)&lt;br /&gt;
draw.text((width - (bbox[2]-bbox[0]) - 3, 0), price_str, font=f_price, fill=0)&lt;br /&gt;
&lt;br /&gt;
# 등락 + 페이지 라벨&lt;br /&gt;
sym = change_symbol(stock[&amp;#039;sign&amp;#039;])&lt;br /&gt;
chg_str = f&amp;quot;{sym} {abs(stock[&amp;#039;change&amp;#039;]):,} ({stock[&amp;#039;change_rate&amp;#039;]:+.2f}%)&amp;quot;&lt;br /&gt;
draw.text((3, 18), chg_str, font=f_chg, fill=0)&lt;br /&gt;
&lt;br /&gt;
label = f&amp;#039;주봉 {len(chart_data)}주&amp;#039;&lt;br /&gt;
bbox = draw.textbbox((0, 0), label, font=f_tiny)&lt;br /&gt;
draw.text((width - (bbox[2]-bbox[0]) - 3, 21), label, font=f_tiny, fill=0)&lt;br /&gt;
&lt;br /&gt;
draw.line([(0, 32), (width, 32)], fill=0, width=1)&lt;br /&gt;
&lt;br /&gt;
# ── 차트 영역 ──&lt;br /&gt;
cx, cy = 3, 36                  # 좌상단&lt;br /&gt;
cw, ch = 200, 82                 # 폭, 높이 (오른쪽에 라벨 공간 확보)&lt;br /&gt;
&lt;br /&gt;
if not chart_data or len(chart_data) &amp;lt; 2:&lt;br /&gt;
    draw.text((cx + 40, cy + ch//2 - 5), &amp;#039;차트 데이터 없음&amp;#039;, font=f_tiny, fill=0)&lt;br /&gt;
    return image&lt;br /&gt;
&lt;br /&gt;
closes = [c[1] for c in chart_data]&lt;br /&gt;
pmin, pmax = min(closes), max(closes)&lt;br /&gt;
if pmax == pmin:&lt;br /&gt;
    pmax = pmin + 1&lt;br /&gt;
span = pmax - pmin&lt;br /&gt;
&lt;br /&gt;
# 축&lt;br /&gt;
draw.line([(cx, cy), (cx, cy + ch)], fill=0, width=1)&lt;br /&gt;
draw.line([(cx, cy + ch), (cx + cw, cy + ch)], fill=0, width=1)&lt;br /&gt;
&lt;br /&gt;
# 가로 그리드 (중간선)&lt;br /&gt;
mid_y = cy + ch // 2&lt;br /&gt;
for x in range(cx + 2, cx + cw, 6):&lt;br /&gt;
    draw.point((x, mid_y), fill=0)&lt;br /&gt;
&lt;br /&gt;
# 라인 그리기&lt;br /&gt;
n = len(closes)&lt;br /&gt;
pts = []&lt;br /&gt;
for i, c in enumerate(closes):&lt;br /&gt;
    px = cx + 1 + int(i * (cw - 2) / max(n - 1, 1))&lt;br /&gt;
    py = cy + ch - 1 - int((c - pmin) / span * (ch - 3))&lt;br /&gt;
    pts.append((px, py))&lt;br /&gt;
&lt;br /&gt;
for i in range(len(pts) - 1):&lt;br /&gt;
    draw.line([pts[i], pts[i + 1]], fill=0, width=1)&lt;br /&gt;
&lt;br /&gt;
# 현재가(마지막 봉) 강조 표시&lt;br /&gt;
last_x, last_y = pts[-1]&lt;br /&gt;
draw.ellipse([last_x - 2, last_y - 2, last_x + 2, last_y + 2], fill=0)&lt;br /&gt;
&lt;br /&gt;
# Y축 라벨 (오른쪽)&lt;br /&gt;
label_x = cx + cw + 3&lt;br /&gt;
draw.text((label_x, cy - 4),         fmt_axis(pmax), font=f_tiny, fill=0)&lt;br /&gt;
draw.text((label_x, mid_y - 5),      fmt_axis((pmax + pmin) / 2), font=f_tiny, fill=0)&lt;br /&gt;
draw.text((label_x, cy + ch - 9),    fmt_axis(pmin), font=f_tiny, fill=0)&lt;br /&gt;
&lt;br /&gt;
# X축 라벨 (시작 / 끝 날짜)&lt;br /&gt;
if chart_data:&lt;br /&gt;
    d_start = chart_data[0][0]&lt;br /&gt;
    d_end   = chart_data[-1][0]&lt;br /&gt;
    # YYYYMMDD → MM/DD&lt;br /&gt;
    s_str = f&amp;#039;{d_start[4:6]}/{d_start[6:8]}&amp;#039;&lt;br /&gt;
    e_str = f&amp;#039;{d_end[4:6]}/{d_end[6:8]}&amp;#039;&lt;br /&gt;
    draw.text((cx + 2, cy + ch + 1), s_str, font=f_tiny, fill=0)&lt;br /&gt;
    bbox = draw.textbbox((0, 0), e_str, font=f_tiny)&lt;br /&gt;
    draw.text((cx + cw - (bbox[2]-bbox[0]) - 2, cy + ch + 1), e_str, font=f_tiny, fill=0)&lt;br /&gt;
&lt;br /&gt;
return image&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
# 메인 루프&lt;br /&gt;
&lt;br /&gt;
# ─────────────────────────────────────────────────────────────&lt;br /&gt;
&lt;br /&gt;
running = True&lt;br /&gt;
&lt;br /&gt;
def handle_signal(signum, frame):&lt;br /&gt;
global running&lt;br /&gt;
log.info(f”신호 수신({signum}) - 종료 처리”)&lt;br /&gt;
running = False&lt;br /&gt;
&lt;br /&gt;
def render(epd, image, state):&lt;br /&gt;
“”“전체/부분 갱신을 자동 선택해 화면 출력”””&lt;br /&gt;
if state[‘first’] or state[‘partial_count’] &amp;gt;= FULL_REFRESH_EVERY:&lt;br /&gt;
epd.init()&lt;br /&gt;
epd.display(epd.getbuffer(image))&lt;br /&gt;
state[‘partial_count’] = 0&lt;br /&gt;
state[‘first’] = False&lt;br /&gt;
log.info(“전체 갱신”)&lt;br /&gt;
else:&lt;br /&gt;
try:&lt;br /&gt;
epd.displayPartial(epd.getbuffer(image))&lt;br /&gt;
state[‘partial_count’] += 1&lt;br /&gt;
log.info(f”부분 갱신 ({state[‘partial_count’]}/{FULL_REFRESH_EVERY})”)&lt;br /&gt;
except AttributeError:&lt;br /&gt;
epd.display(epd.getbuffer(image))&lt;br /&gt;
log.info(“전체 갱신 (부분 갱신 미지원)”)&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
signal.signal(signal.SIGINT,  handle_signal)&lt;br /&gt;
signal.signal(signal.SIGTERM, handle_signal)&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
log.info(&amp;quot;주가 모니터 시작 (Waveshare 2.13\&amp;quot;)&amp;quot;)&lt;br /&gt;
epd = epd_module.EPD()&lt;br /&gt;
epd.init()&lt;br /&gt;
epd.Clear(0xFF)&lt;br /&gt;
&lt;br /&gt;
stocks_data = [None] * len(STOCKS)&lt;br /&gt;
chart_cache = {}                 # code -&amp;gt; ([(date, close), ...], fetched_at)&lt;br /&gt;
state = {&amp;#039;first&amp;#039;: True, &amp;#039;partial_count&amp;#039;: 0}&lt;br /&gt;
&lt;br /&gt;
total_pages = 1 + len(STOCKS)    # 요약 + 종목별 차트&lt;br /&gt;
current_page = 0&lt;br /&gt;
&lt;br /&gt;
last_data_fetch = 0&lt;br /&gt;
last_page_switch = time.time()&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while running:&lt;br /&gt;
        now = time.time()&lt;br /&gt;
        need_redraw = False&lt;br /&gt;
&lt;br /&gt;
        # ── 시세 갱신 ──&lt;br /&gt;
        interval = DATA_REFRESH_OPEN if is_market_hours() else DATA_REFRESH_CLOSE&lt;br /&gt;
        if now - last_data_fetch &amp;gt;= interval:&lt;br /&gt;
            for i, s in enumerate(STOCKS):&lt;br /&gt;
                d = fetch_stock(s[&amp;#039;code&amp;#039;])&lt;br /&gt;
                stocks_data[i] = d&lt;br /&gt;
                if d:&lt;br /&gt;
                    log.info(f&amp;quot;{d[&amp;#039;name&amp;#039;]:8s} {d[&amp;#039;price&amp;#039;]:&amp;gt;8,}  &amp;quot;&lt;br /&gt;
                             f&amp;quot;{change_symbol(d[&amp;#039;sign&amp;#039;])}{abs(d[&amp;#039;change&amp;#039;]):&amp;gt;6,}  &amp;quot;&lt;br /&gt;
                             f&amp;quot;({d[&amp;#039;change_rate&amp;#039;]:+.2f}%)&amp;quot;)&lt;br /&gt;
            last_data_fetch = now&lt;br /&gt;
            need_redraw = True&lt;br /&gt;
&lt;br /&gt;
        # ── 주봉 캐시 갱신 ──&lt;br /&gt;
        for s in STOCKS:&lt;br /&gt;
            code = s[&amp;#039;code&amp;#039;]&lt;br /&gt;
            cached = chart_cache.get(code)&lt;br /&gt;
            if cached is None or now - cached[1] &amp;gt;= CHART_CACHE_TTL:&lt;br /&gt;
                log.info(f&amp;quot;[{code}] 주봉 조회&amp;quot;)&lt;br /&gt;
                chart = fetch_weekly_chart(code)&lt;br /&gt;
                chart_cache[code] = (chart, now)&lt;br /&gt;
                need_redraw = True&lt;br /&gt;
&lt;br /&gt;
        # ── 페이지 전환 ──&lt;br /&gt;
        if now - last_page_switch &amp;gt;= PAGE_DURATION:&lt;br /&gt;
            current_page = (current_page + 1) % total_pages&lt;br /&gt;
            last_page_switch = now&lt;br /&gt;
            need_redraw = True&lt;br /&gt;
            log.info(f&amp;quot;페이지 전환 → {current_page}&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        # ── 그리기 ──&lt;br /&gt;
        if need_redraw:&lt;br /&gt;
            if current_page == 0:&lt;br /&gt;
                image = build_summary_image(epd, stocks_data)&lt;br /&gt;
            else:&lt;br /&gt;
                idx = current_page - 1&lt;br /&gt;
                code = STOCKS[idx][&amp;#039;code&amp;#039;]&lt;br /&gt;
                chart = chart_cache.get(code, ([], 0))[0]&lt;br /&gt;
                image = build_chart_image(epd, stocks_data[idx], chart)&lt;br /&gt;
            render(epd, image, state)&lt;br /&gt;
&lt;br /&gt;
        # 1초 단위로 깨어나서 페이지/데이터 시점 체크&lt;br /&gt;
        for _ in range(1):&lt;br /&gt;
            if not running:&lt;br /&gt;
                break&lt;br /&gt;
            time.sleep(1)&lt;br /&gt;
&lt;br /&gt;
except Exception as e:&lt;br /&gt;
    log.exception(f&amp;quot;오류: {e}&amp;quot;)&lt;br /&gt;
finally:&lt;br /&gt;
    log.info(&amp;quot;e-Paper 정리&amp;quot;)&lt;br /&gt;
    try:&lt;br /&gt;
        epd.init()&lt;br /&gt;
        epd.Clear(0xFF)&lt;br /&gt;
        epd.sleep()&lt;br /&gt;
    except Exception:&lt;br /&gt;
        pass&lt;br /&gt;
    log.info(&amp;quot;종료 완료&amp;quot;)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
if **name** == ‘**main**’:&lt;br /&gt;
main()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Devcafe</name></author>
	</entry>
</feed>