1. API입력결과를 OLED에 표시하기
앞선 글들에서 기상청의 단기 예보 API 이용 방법을 소개했었고 (https://kongyine.com/223208832718 ) , 이러한 API를 활용해서 기상정보를 라즈베리파이 피코보드에서 직접 받아들이는 방법을 다음의 글에서 소개한 바 있었다. https://kongyine.com/223210593866
이렇게 라즈베리파이 피코에서 불러들인 기상예보값을 OLED 화면에 표시해 보기로 했다.
OLED 화면이 128×64화소인 점과, 글자 한자는 8×9 화소를 사용하는 점을 고려해서, 우선 다음과 같이
* 예측날자와 기준시간을 표시하고,
* 그날의 최저온도와 최고온도른 숫자로 표시하고
* 24시간 기준 온도 변화 경향을 간단한 그래프 형태로 표시해 보기로 했다.
2. 예제코드
앞선 글들에서 기상청의 단기 예보 API 이용 방법을 소개했었고 (https://kongyine.com/223208
이 과정에서 사용한 Code는 다음과 같다.
import network
import utime
import urequests
from ssd1306 import SSD1306_I2C
from machine import Pin, I2C
WIDTH =128
HEIGHT= 64
i2c=I2C(0,scl=Pin(1),sda=Pin(0),freq=200000)
oled = SSD1306_I2C(WIDTH,HEIGHT,i2c)
oled.init_display()
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.scan( ) #--> Scan
SSID = "SSID"
PASSWORD = "PASSWORD"
wlan.connect(SSID, PASSWORD)
while not wlan.isconnected() and wlan.status() >= 0:
print("Waiting to connect:")
utime.sleep(2)
if wlan.status() != 3:
raise RuntimeError('network connection failed')
else:
print("Wifi is connected == ", wlan.isconnected(), "ip =", wlan.ifconfig())
now=utime.localtime()
year=str(now[0])
month=str(now[1])
if len(month)<2:
month="0"+ month
date=str(now[2])
if len(date)<2:
date="0"+ date
base_time="0200"
base_date=year+month+date
numOfRows=290
pageNo=1
nx=55
ny=127
apiaddress="http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst?"
mykey="serviceKey="+"nwpJP0DaMXFxvpnKbGX5T%2B7y%2BLEhweTo53dcx14a0KQ0yL7LYsLhKGkJpLDx45SsC02IpFbkPanh0XpftSYB3A%3D%3D"
I_format="&numOfRows="+str(numOfRows)+"&pageNo="+str(pageNo)+"&dataType=JSON"
S_point="&base_date="+str(base_date)+"&base_time="+str(base_time)
whereisit="&nx="+str(nx)+"&ny="+str(ny)
yebo = urequests.get(apiaddress+mykey+I_format+S_point+whereisit).json()
number = yebo['response']['body']['numOfRows']
TMP=[]
fdate=[]
ftime=[]
print ("예측기준일시", base_date, base_time)
for i in range(number):
if (yebo['response']['body']['items']['item'][i]['category'])=="TMX":
TMX=yebo['response']['body']['items']['item'][i]['fcstValue']
if (yebo['response']['body']['items']['item'][i]['category'])=="TMN":
TMN=yebo['response']['body']['items']['item'][i]['fcstValue']
if (yebo['response']['body']['items']['item'][i]['category'])=="TMP":
TMP.append(yebo['response']['body']['items']['item'][i]['fcstValue'])
fdate.append(yebo['response']['body']['items']['item'][i]['fcstDate'])
ftime.append(yebo['response']['body']['items']['item'][i]['fcstTime'])
for i in range(len(ftime)):
while True:
oled.fill(0)
oled.text(base_date+" "+base_time, 0, 0)
oled.text("L:"+TMN+" H:"+TMX, 0, 8)
oled.text(TMX, 0, 16)
oled.text(TMN, 0, 48)
x=24
y=55
oled.rect(x,y,96,16,1)
oled.text("0", x, y+2)
oled.text("24", x+96-8, y+2)
for k in range(23):
x1=x+4
y1=round(54-38*(float(TMP[k+1])-float(TMN))/(float(TMX)-float(TMN)))
oled.line(x,y,x1,y1,1)
x=x1
y=y1
oled.show()
utime.sleep(0.3)
utime.sleep(5)
wlan.disconnect( )
구현후 동작하는 모습은 다음과 같다.

코드에 대한 설명을 하자면
우선 다음 코드로 API로부터 기상정보를 JSON형태로 불러오게 되고,
yebo = urequests.get(apiaddress+mykey+I_format+S_point+whereisit).json()
여기서 예보의 수를 확인하고
number = yebo[‘response’][‘body’][‘numOfRows’]
읽어온 값중에서 예측온도 값과, 이때의 시간값을 저장하기 위한 배열을 만들고,
TMP=[ ]
fdate=[ ]
ftime=[ ]
예측치중에서 최대치값과, 최소치값을 확인하고, 각 시간별 온도예측치를 골라내어 배열에 저장했다.
for i in range(number):
if (yebo[‘response’][‘body’][‘items’][‘item’][i][‘category’])==”TMX”:
TMX=yebo[‘response’][‘body’][‘items’][‘item’][i][‘fcstValue’]
if (yebo[‘response’][‘body’][‘items’][‘item’][i][‘category’])==”TMN”:
TMN=yebo[‘response’][‘body’][‘items’][‘item’][i][‘fcstValue’]
if (yebo[‘response’][‘body’][‘items’][‘item’][i][‘category’])==”TMP”:
TMP.append(yebo[‘response’][‘body’][‘items’][‘item’][i][‘fcstValue’])
fdate.append(yebo[‘response’][‘body’][‘items’][‘item’][i][‘fcstDate’])
ftime.append(yebo[‘response’][‘body’][‘items’][‘item’][i][‘fcstTime’])
그리고, OLED에 예측기준 날자와 기준 시간, 그리고 확인된 최저온도와 최고온도예측치를 효시했다.
while True:
oled.fill(0)
oled.text(base_date+” “+base_time, 0, 0)
oled.text(“L:”+TMN+” H:”+TMX, 0, 8)
그리고, OLED에 4각형을 그리고, 최저치와 최고치를 y축의 양끝점으로 하도록 값을 표기하고,
x축으로는 향후 24시간을 의미하는 0과 24를 표기하도록 했다. 이를 표기하는 좌표는 사각형을 그리는 원점(=아래의 x,y 값)에서 아래로 2개 픽셀만큼 띄어진 곳(=y+2)행과, 시작점 x와, 1시간당 4개픽셀을 계산한값에서 24가 2자리임을 고려하여 -8만큼 픽셀을 이동한 곳에 24가 표기되도록 했다.
oled.text(TMX, 0, 16)
oled.text(TMN, 0, 48)
x=24
y=55
oled.rect(x,y,96,16,1)
oled.text(“0”, x, y+2)
oled.text(“24”, x+96-8, y+2)
이렇게 그려진 4각형에, 시간별 예측온도를 토대로, 선그래프를 쭉 이어서 그리도록 했다.
시간을 나타내는 X축은 1시간당 4개의 화소수가 증가되도록 할당했고, 수직축은 상단부 2줄과 마지말 1줄에 각각 8개 화소씩을 계산해서 좌표를 계산했다. 최종적인 최적 좌표치 값은 조금 더 모양을 보아가면서 조정하려 한다.
for k in range(23):
x1=x+4
y1=round(54-38*(float(TMP[k+1])-float(TMN))/(float(TMX)-float(TMN)))
oled.line(x,y,x1,y1,1)
x=x1
y=y1
oled.show()
utime.sleep(0.2)
3. TMN과 TMX 활용에 대한 고민
앞선 글들에서 기상청의 단기 예보 API 이용 방법을 소개했었고 (https://kongyine.com/223208
이렇게 예측온도를 표시하면서 발견한게 있었다.
처음생각에는 예측온도중에 최고온도에 해당되는 TMX 예측치 및 최저온도 예측치인 TMN과 동일한 값이 당연히 있을것이란 생각했었는데, 막상 확인해 보니 그렇지 않았다.
실제 예측치를 자세히 조사해 보니, 최고온도를 나타내는 TMX의 경우 다음과 같았고,
최저온도를 나타내는 TMN의 경우 다음과 같았다.
나는 위의 시간대에서 TMP와 TMX 또는 TMN이 일시적으로 같아지리라 생각했으나, 그렇지 않았던 것이다.
즉, API에서 제공하는 단기예보는 특정시각의 온도이고, 다음시각으로 넘어가는 중간의 시점 어딘가에서 각기 최고온도와 최저온도가 존재하는 것이었다. 이러한 현상은 단기예보가 1시간 단위의 예보이기 때문에 나타나는 현상인듯 하고, 1시간 간격과 별개로 좀 더 세밀한 예보치에서 얻어진 일시적인 예측온도 TMN과 TMP가 1시간 단위예보 중간에 끼워서 나오는 듯 하다. (아마도 시간간격이 촘촘한 초단기예보등에서는 두개의 값들이 수렴하지 않을까 싶다.)
이러한 현상때문에, TMN과 TMX로 나온 값을 최저온도와 최고온도로 표시해야 할지, 아니면 TMP로 나오는 예측온도들중의 최소값과 최고값을 활용할지에 대한 고민이 있었다.

