<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://yanghuiwon22.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://yanghuiwon22.github.io/" rel="alternate" type="text/html" /><updated>2025-02-25T07:48:13+00:00</updated><id>https://yanghuiwon22.github.io/feed.xml</id><title type="html">Yanghuiwon</title><subtitle>A website with blog posts and pages</subtitle><entry><title type="html">[연구실 대시보드] 네이버 날씨 크롤링하기</title><link href="https://yanghuiwon22.github.io/demo/2025/02/25/%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%82%A0%EC%94%A8-%ED%81%AC%EB%A1%A4%EB%A7%81.html" rel="alternate" type="text/html" title="[연구실 대시보드] 네이버 날씨 크롤링하기" /><published>2025-02-25T00:00:00+00:00</published><updated>2025-02-25T00:00:00+00:00</updated><id>https://yanghuiwon22.github.io/demo/2025/02/25/%EB%84%A4%EC%9D%B4%EB%B2%84%20%EB%82%A0%EC%94%A8%20%ED%81%AC%EB%A1%A4%EB%A7%81</id><content type="html" xml:base="https://yanghuiwon22.github.io/demo/2025/02/25/%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%82%A0%EC%94%A8-%ED%81%AC%EB%A1%A4%EB%A7%81.html"><![CDATA[<p>크롤링을 이용하여 네이버 날씨를 대시보드에 추가하고자 한다.</p>

<hr />
<h3 id="문제상황해결방안">문제상황&amp;해결방안</h3>
<p>대시보드에 날씨 정보를 추가하려고 한다. 공공데이터포털의 api 서비스를 이용하려고 했으나, 데이터 업데이트 간격이 1시간이었다.
5분 정도의 정밀한 데이터를 원했기에 네이버 날씨를 활용하고자 한다.</p>

<p><strong>네이버 날씨 사용의 이점</strong></p>
<ul>
  <li>미세먼지, 초미세먼지 정보 한번에 수집 가능</li>
  <li>날씨 요약 정보(구름, 맑음 등) 파악 가능</li>
</ul>

<hr />
<h3 id="핵심코드해결과정">핵심코드&amp;해결과정</h3>
<h4 id="selenium을-통한-크롤링-진행-">selenium을 통한 크롤링 진행 <br /></h4>
<p>[오류] 드라이버 로드 실패</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>selenium.common.exceptions.NoSuchDriverException: Message: Unable to obtain driver for chrome; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors/driver_location
</code></pre></div></div>
<ul>
  <li>드라이버 경로가 잘못 잡혀있어 다운로드 후 진행 -&gt; 해결 안됌.</li>
  <li>크롬과 크롬 드리이버 버전 확인 –&gt; 일치 <br />
==&gt; 도데체 왜 안되는것인가?? <br />
자동으로 크롬 버전 확인 후 드라이버 설치하는 도구 사용 –&gt; 해결</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">!</span><span class="n">pip</span> <span class="n">intall</span> <span class="n">webdriver</span><span class="o">-</span><span class="n">manager</span>

<span class="kn">from</span> <span class="nn">webdriver_manager.chrome</span> <span class="kn">import</span> <span class="n">ChromeDriverManager</span>
<span class="n">service</span> <span class="o">=</span> <span class="n">Service</span><span class="p">(</span><span class="n">service</span><span class="o">=</span><span class="n">Service</span><span class="p">(</span><span class="n">ChromeDriverManager</span><span class="p">().</span><span class="n">install</span><span class="p">()))</span>
</code></pre></div></div>

<p>그렇다면 코드를 실행할 때마다 크롬 드라이버를 설치하는 것인가?
==&gt; 아니다. 이전 버전과 동일한 크로 드라이버를 사용할 경우, 로컬 캐시를 사용한다 (즉, 버전이 바뀌면 알아서 맞게 바뀐다)</p>

<p>설치가 되는 위치는 (윈도우 기준) .wdm 폴더를 사용한다 (캐시 저장소)
<img src="img.png" alt="img.png" />
(확인 해보니 실제로 존재!)</p>

<h4 id="네이버-날씨의-디자인-반영하기">네이버 날씨의 디자인 반영하기</h4>
<p><img src="img_1.png" alt="img_1.png" /></p>

<hr />
<h3 id="참고링크">참고링크</h3>
<p>항상 나의 손과 발이 되어주는 chatgpt에서 감사드린다.</p>]]></content><author><name></name></author><category term="Demo" /><category term="naver-weather" /><category term="dashboard" /><category term="selenium" /><category term="crawling" /><summary type="html"><![CDATA[크롤링을 이용하여 네이버 날씨를 대시보드에 추가하고자 한다.]]></summary></entry><entry><title type="html">[연구실 대시보드] 구글 캘린더 연결하기</title><link href="https://yanghuiwon22.github.io/demo/2024/11/07/%EC%97%B0%EA%B5%AC%EC%8B%A4-slack-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0.html" rel="alternate" type="text/html" title="[연구실 대시보드] 구글 캘린더 연결하기" /><published>2024-11-07T00:00:00+00:00</published><updated>2024-11-07T00:00:00+00:00</updated><id>https://yanghuiwon22.github.io/demo/2024/11/07/%EC%97%B0%EA%B5%AC%EC%8B%A4-slack-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</id><content type="html" xml:base="https://yanghuiwon22.github.io/demo/2024/11/07/%EC%97%B0%EA%B5%AC%EC%8B%A4-slack-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0.html"><![CDATA[<p>실시간 데이터가 들어오지 않을 시, 과거 데이터를 출력해준다.</p>

<h1 id="문제상황">문제상황</h1>
<ul>
  <li>api를 통해 <strong>실시간 데이터가 들어오지 않을 땐</strong> <strong>과거값 출력</strong>하도록 설정</li>
  <li><strong>현재</strong> 실시간데이터가 들어오고 있는지, 랜덤값이 출력되고 있는지 <strong>알 수 없음</strong></li>
</ul>

<h1 id="해결방안">해결방안</h1>

<ol>
  <li>랜덤값을 출력할 땐, text로 표시</li>
  <li>데이터로드 시간을 출력</li>
</ol>

<h1 id="핵심코드해결과정">핵심코드&amp;해결과정</h1>

<h3 id="랜덤값을-출력할-땐-text로-표시">랜덤값을 출력할 땐, text로 표시</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">player</span><span class="p">.</span><span class="n">pos_layer</span> <span class="o">==</span> <span class="s">'mini_chamber'</span><span class="p">:</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">livedata_mini_chamber</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_fake</span><span class="p">(</span><span class="n">top</span><span class="o">=</span><span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">bottom</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li>
    <p>위의 코드를 보면 실시간 데이터가 들어올 때 true / 안들어올 때 false 로 livedata_mini_chamber를 선언했다</p>
  </li>
  <li><code class="language-plaintext highlighter-rouge">response.status_code == 200</code> 가 아닐 때, livedata_mini_chamber를 false로 설정</li>
  <li>현재의 경우, 데이터는 들어오는데 실시간 데이터가 아닌 과거의 데이터가 들어오고 있음.</li>
  <li>이를 해결하기 위해 현재시간과 데이터로드 시간을 비교하여 3분이 지났을 때, livedata_mini_chamber를 false로 설정하도록 함
(데이터 로드 기간 : 1분)</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">set_time</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">output</span><span class="p">[</span><span class="s">'Time'</span><span class="p">],</span> <span class="p">(</span><span class="s">'%H:%M:%S'</span><span class="p">))</span>
<span class="k">if</span> <span class="p">(</span><span class="n">datetime</span><span class="p">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">set_time</span><span class="p">).</span><span class="n">seconds</span> <span class="o">/</span> <span class="mi">60</span> <span class="o">&gt;=</span> <span class="mi">3</span><span class="p">:</span>
    <span class="bp">self</span><span class="p">.</span><span class="n">livedata_mini_chamber</span> <span class="o">=</span> <span class="bp">False</span>
</code></pre></div></div>

<p><img src="https://Yanghuiwon22.github.io/assets/img/feature-img/2024-08-20-1.png" /></p>
<p style="color: royalblue">'현재 실시간 데이터가 들어오고 있지 않다 : 보여지는 데이터는 과거의 데이터이다.'가 출력되고 있다</p>

<h3 id="데이터로드-시간을-출력">데이터로드 시간을 출력</h3>

<p>텍스트를 대시보드(회색컴퓨터)의 오른쪽 하단에 출력하기 위해서 텍스트 작업을 진행</p>

<p>텍스트를 파이게임 내에서 출력하기 위해서</p>
<ol>
  <li>text_surf  —&gt; 그리고자 하는 글자</li>
  <li>text_rect  —&gt; 글자를 담을 공간 <br />
위 두가지가 필요하다</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">show_entry_updated_time</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text_surf</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'black'</span><span class="p">):</span>
    <span class="n">updateed_time_surf</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">font</span><span class="p">.</span><span class="n">render</span><span class="p">(</span><span class="n">text_surf</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="p">)</span>
    <span class="n">top</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">bottom</span> <span class="o">-</span> <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_height</span><span class="p">()</span> <span class="o">-</span> <span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="o">*</span><span class="mi">3</span>
    <span class="n">updated_time_rect</span> <span class="o">=</span> <span class="n">pygame</span><span class="p">.</span><span class="n">Rect</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">right</span><span class="o">-</span><span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_width</span><span class="p">()</span><span class="o">-</span><span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="o">*</span><span class="mi">3</span><span class="p">,</span> <span class="n">top</span><span class="p">,</span>
                                    <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_width</span><span class="p">(),</span> <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_height</span><span class="p">())</span>

    <span class="bp">self</span><span class="p">.</span><span class="n">updated_time_rect</span> <span class="o">=</span> <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_rect</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">updated_time_rect</span><span class="p">.</span><span class="n">centerx</span><span class="p">,</span> <span class="n">updated_time_rect</span><span class="p">.</span><span class="n">centery</span><span class="p">))</span>
    <span class="bp">self</span><span class="p">.</span><span class="n">display_surface</span><span class="p">.</span><span class="n">blit</span><span class="p">(</span><span class="n">updateed_time_surf</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">updated_time_rect</span><span class="p">)</span>
</code></pre></div></div>

<p>위 코드에서 보면</p>
<ol>
  <li>text_surf로 그리고자하는 text를 받느다</li>
  <li>updateed_time_surf에 파이게임 내에서 사용할 수 있는데 텍스트의 형태로 변환한다</li>
  <li>text를 그리고자 하는 위치, 크기를 정한다</li>
  <li>text를 그리고자 하는 위치에 text를 그린다
의 순서로 되어있는 것을 확인할 수 있다.</li>
</ol>

<p>실시간 데이터를 받아오던 함수에서 return값을 리스트로 받아왔는데, 앞으로 리스트의 요소가 늘 것을 우려
그 경우, 프로그램 내에서 해당부분을 모두 수정해야 하므로 딕셔너리로 받아오도록 수정</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">player</span><span class="p">.</span><span class="n">pos_layer</span> <span class="o">==</span> <span class="s">'mini_chamber'</span><span class="p">:</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">livedata_mini_chamber</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_updated_time</span><span class="p">(</span><span class="sa">f</span><span class="s">'UPDATED TIME : </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Date"</span><span class="p">]</span><span class="si">}</span><span class="s"> </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Time"</span><span class="p">]</span><span class="si">}</span><span class="s">'</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'red'</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_fake</span><span class="p">(</span><span class="n">top</span><span class="o">=</span><span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">bottom</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_updated_time</span><span class="p">(</span><span class="sa">f</span><span class="s">'UPDATED TIME : </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Date"</span><span class="p">]</span><span class="si">}</span><span class="s"> </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Time"</span><span class="p">]</span><span class="si">}</span><span class="s">'</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
</code></pre></div></div>
<p>앞에서 걸었던 조건에 방금 추가한 기능을 합쳐 코드를 작성하였다
실시간 데이터가 아닐 경우, 업데이트 시간을 빨간색으로 표시하여 사용자에게 알리도록 하였다.</p>

<p><img src="https://Yanghuiwon22.github.io/assets/img/feature-img/2024-08-20-2.png" /></p>
<p style="color: royalblue">데이터 로드 시간을 출력하고 있다</p>]]></content><author><name></name></author><category term="Demo" /><category term="flask" /><category term="dashboard" /><category term="google-calender" /><category term="google" /><summary type="html"><![CDATA[실시간 데이터가 들어오지 않을 시, 과거 데이터를 출력해준다.]]></summary></entry><entry><title type="html">[연구실 대시보드] 구글 캘린더 연결하기</title><link href="https://yanghuiwon22.github.io/demo/2024/11/07/%EC%B9%B4%EC%B9%B4%EC%98%A4%EC%B1%97%EB%B4%87-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0.html" rel="alternate" type="text/html" title="[연구실 대시보드] 구글 캘린더 연결하기" /><published>2024-11-07T00:00:00+00:00</published><updated>2024-11-07T00:00:00+00:00</updated><id>https://yanghuiwon22.github.io/demo/2024/11/07/%EC%B9%B4%EC%B9%B4%EC%98%A4%EC%B1%97%EB%B4%87-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</id><content type="html" xml:base="https://yanghuiwon22.github.io/demo/2024/11/07/%EC%B9%B4%EC%B9%B4%EC%98%A4%EC%B1%97%EB%B4%87-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0.html"><![CDATA[<p>카카오챗봇을 이용하여 웹 대시보드의 알람을 휴대폰으로 전송한다.</p>

<h3 id="문제상황">문제상황</h3>

<h3 id="해결방안">해결방안</h3>

<h3 id="핵심코드해결과정">핵심코드&amp;해결과정</h3>

<h3 id="참고링크">참고링크</h3>
<p>rest-api를 활용하여 카카오톡 챗봇 만들기
https://medium.com/@kjwan4435/rest-api%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%98%EC%97%AC-%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%86%A1-%EC%B1%97%EB%B4%87-%EB%A7%8C%EB%93%A4%EA%B8%B0-1%ED%8E%B8-f647334d5128</p>]]></content><author><name></name></author><category term="Demo" /><category term="flask" /><category term="dashboard" /><category term="google-calender" /><category term="google" /><summary type="html"><![CDATA[카카오챗봇을 이용하여 웹 대시보드의 알람을 휴대폰으로 전송한다.]]></summary></entry><entry><title type="html">[연구실 대시보드] 구글 캘린더 리프레시 토큰 얻기</title><link href="https://yanghuiwon22.github.io/demo/2024/11/04/%EC%97%B0%EA%B5%AC%EC%8B%A4-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EA%B5%AC%EA%B8%80-%EC%BA%98%EB%A6%B0%EB%8D%94-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0.html" rel="alternate" type="text/html" title="[연구실 대시보드] 구글 캘린더 리프레시 토큰 얻기" /><published>2024-11-04T00:00:00+00:00</published><updated>2024-11-04T00:00:00+00:00</updated><id>https://yanghuiwon22.github.io/demo/2024/11/04/%EC%97%B0%EA%B5%AC%EC%8B%A4-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EA%B5%AC%EA%B8%80-%EC%BA%98%EB%A6%B0%EB%8D%94-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</id><content type="html" xml:base="https://yanghuiwon22.github.io/demo/2024/11/04/%EC%97%B0%EA%B5%AC%EC%8B%A4-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EA%B5%AC%EA%B8%80-%EC%BA%98%EB%A6%B0%EB%8D%94-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0.html"><![CDATA[<p>연구실 대시보드에 <strong>구글 캘린더를 연동</strong>하여 구성원들의 <strong>일정을 확인</strong>한다.</p>

<h3 id="구현목표">구현목표</h3>
<ul>
  <li>연구실 구성원들의 일정을 파악하기 위한 기능을 구현하고자 한다.
    <ol>
      <li>우선적으로 slack을 통해 재적 상태를 확인한다.</li>
      <li>현재 재적중이지 않은 구성원의 경우 고정적인 스케줄을 적어둔 연구실 일정표(구글 시트) <br />
<strong>3. 현재 재적중이지 않은 구성원의 경우 연구실 캘린더(구글 캘린더)를 참고하도록 한다.</strong> (현재 진행중)</li>
    </ol>
  </li>
</ul>

<h2 id="문제상황">문제상황</h2>
<p>토큰의 유효기간이 하루여서 매일 로그인하여 인증해야하는 문제가 발생하였다. <br />
따라서 이를 해결하고자 chatGPT에게 해결방법을 물어보았다.</p>

<p><strong>chatGPT - 질문</strong><br /></p>
<blockquote>
  <p>구글 캘린더에서 이벤트들을 불러오는 코드를 짜고 있는데, 토큰이 하루만에 만료되는 거 같아. <br />
코드를 통해서 토큰을 불러올 수 있는데 그러면 로그인을 해야해. 서버에 올려둘예정인데 해결방법이 있을까</p>
</blockquote>

<p><strong>chatGPT - 답변</strong> <br /></p>
<blockquote>
  <p>구글 캘린더 API에서 토큰이 하루 만에 만료되는 문제를 해결하려면 OAuth 2.0의 리프레시 토큰을 활용하는 것이 좋습니다.
리프레시 토큰 활용:
리프레시 토큰은 접근 토큰이 만료되었을 때 자동으로 새로운 접근 토큰을 요청하는 데 사용됩니다.
초기 인증 시 offline 모드를 설정해 리프레시 토큰을 받습니다. 이 토큰은 만료되지 않으므로, 사용자가 다시 로그인할 필요 없이 자동 갱신이 가능합니다.
자동 갱신 코드 추가:
매번 요청 전에 접근 토큰의 유효성을 확인하고, 만료되었을 경우 리프레시 토큰을 통해 자동으로 갱신하도록 설정합니다.</p>
  <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">google.oauth2.credentials</span> <span class="kn">import</span> <span class="n">Credentials</span>
<span class="kn">from</span> <span class="nn">google.auth.transport.requests</span> <span class="kn">import</span> <span class="n">Request</span>

<span class="n">creds</span> <span class="o">=</span> <span class="n">Credentials</span><span class="p">(</span><span class="n">token</span><span class="o">=</span><span class="s">'YOUR_ACCESS_TOKEN'</span><span class="p">,</span>
                   <span class="n">refresh_token</span><span class="o">=</span><span class="s">'YOUR_REFRESH_TOKEN'</span><span class="p">,</span>
                   <span class="n">token_uri</span><span class="o">=</span><span class="s">'https://oauth2.googleapis.com/token'</span><span class="p">,</span>
                   <span class="n">client_id</span><span class="o">=</span><span class="s">'YOUR_CLIENT_ID'</span><span class="p">,</span>
                   <span class="n">client_secret</span><span class="o">=</span><span class="s">'YOUR_CLIENT_SECRET'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">creds</span><span class="p">.</span><span class="n">expired</span> <span class="ow">and</span> <span class="n">creds</span><span class="p">.</span><span class="n">refresh_token</span><span class="p">:</span>
   <span class="n">creds</span><span class="p">.</span><span class="n">refresh</span><span class="p">(</span><span class="n">Request</span><span class="p">())</span>
</code></pre></div>  </div>
  <p>보안 유지:
리프레시 토큰과 클라이언트 비밀키를 안전하게 저장합니다. 서버 환경에서는 환경 변수나 비밀 관리 도구를 사용하는 것이 좋습니다.
이렇게 설정하면 사용자 로그인 없이 서버에서 자동으로 토큰을 갱신하면서 구글 캘린더 데이터를 가져올 수 있습니다.`</p>
</blockquote>

<h1 id="핵심코드해결과정">핵심코드&amp;해결과정</h1>

<ol>
  <li>인증코드 받기 <br />
`
https://accounts.google.com/o/oauth2/auth?
client_id=YOUR_CLIENT_ID&amp;
redirect_uri=YOUR_REDIRECT_URI&amp;
scope=https://www.googleapis.com/auth/calendar
&amp;response_type=code&amp;access_type=offline`</li>
</ol>

<p>위의 링크에 맞는 id, uri를 입력하여 code를 얻는다.</p>

<ol>
  <li>인증코드로 토큰 교환하기
```python
import requests</li>
</ol>

<p>url = ‘https://oauth2.googleapis.com/token’</p>

<p>data = {
    ‘code’: ‘AUTH_CODE_FROM_PREVIOUS_STEP’,
    ‘client_id’: ‘YOUR_CLIENT_ID’,
    ‘client_secret’: ‘YOUR_CLIENT_SECRET’,
    ‘redirect_uri’: ‘YOUR_REDIRECT_URI’,
    ‘grant_type’: ‘authorization_code’
}</p>

<p>response = requests.post(url, data=data)
```
1번 단계로 얻은 코드 등을 활용하여 refresh_code를 얻는다.</p>

<h3 id="참고사항">참고사항</h3>
<p>redirect_uri를 바꾸어서 다시 시도했더니 성공했다. <br />
<strong>시도한 redirect_url</strong> : <code class="language-plaintext highlighter-rouge">http://localhost:63710/flowName=GeneralOAuthFlow</code></p>

<p>처음 시도한 uri와 다시 시도한 uri의 차이점은 모르겠다. <br />
다만 credentials.json에 저장된 redirect_uri와 일치하는 것을 확인했다.</p>

<p>credentials.json 파일은 처음 구글 캘린더의 일정을 불러오기 위해 사용한 것으로 추정된다.</p>]]></content><author><name></name></author><category term="Demo" /><category term="flask" /><category term="dashboard" /><category term="google-calender" /><category term="google" /><summary type="html"><![CDATA[연구실 대시보드에 구글 캘린더를 연동하여 구성원들의 일정을 확인한다.]]></summary></entry><entry><title type="html">[chamber-sf] 과거값 표시하기</title><link href="https://yanghuiwon22.github.io/demo/2024/08/20/chamber-sf-%EA%B3%BC%EA%B1%B0%EA%B0%92-%ED%91%9C%EC%8B%9C%ED%95%98%EA%B8%B0.html" rel="alternate" type="text/html" title="[chamber-sf] 과거값 표시하기" /><published>2024-08-20T00:00:00+00:00</published><updated>2024-08-20T00:00:00+00:00</updated><id>https://yanghuiwon22.github.io/demo/2024/08/20/chamber-sf-%EA%B3%BC%EA%B1%B0%EA%B0%92-%ED%91%9C%EC%8B%9C%ED%95%98%EA%B8%B0</id><content type="html" xml:base="https://yanghuiwon22.github.io/demo/2024/08/20/chamber-sf-%EA%B3%BC%EA%B1%B0%EA%B0%92-%ED%91%9C%EC%8B%9C%ED%95%98%EA%B8%B0.html"><![CDATA[<p>실시간 데이터가 들어오지 않을 시, 과거 데이터를 출력해준다.</p>

<h1 id="문제상황">문제상황</h1>
<ul>
  <li>api를 통해 <strong>실시간 데이터가 들어오지 않을 땐</strong> <strong>과거값 출력</strong>하도록 설정</li>
  <li><strong>현재</strong> 실시간데이터가 들어오고 있는지, 랜덤값이 출력되고 있는지 <strong>알 수 없음</strong></li>
</ul>

<h1 id="해결방안">해결방안</h1>

<ol>
  <li>랜덤값을 출력할 땐, text로 표시</li>
  <li>데이터로드 시간을 출력</li>
</ol>

<h1 id="핵심코드해결과정">핵심코드&amp;해결과정</h1>

<h3 id="랜덤값을-출력할-땐-text로-표시">랜덤값을 출력할 땐, text로 표시</h3>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">player</span><span class="p">.</span><span class="n">pos_layer</span> <span class="o">==</span> <span class="s">'mini_chamber'</span><span class="p">:</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">livedata_mini_chamber</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_fake</span><span class="p">(</span><span class="n">top</span><span class="o">=</span><span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">bottom</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li>
    <p>위의 코드를 보면 실시간 데이터가 들어올 때 true / 안들어올 때 false 로 livedata_mini_chamber를 선언했다</p>
  </li>
  <li><code class="language-plaintext highlighter-rouge">response.status_code == 200</code> 가 아닐 때, livedata_mini_chamber를 false로 설정</li>
  <li>현재의 경우, 데이터는 들어오는데 실시간 데이터가 아닌 과거의 데이터가 들어오고 있음.</li>
  <li>이를 해결하기 위해 현재시간과 데이터로드 시간을 비교하여 3분이 지났을 때, livedata_mini_chamber를 false로 설정하도록 함
(데이터 로드 기간 : 1분)</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">set_time</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">output</span><span class="p">[</span><span class="s">'Time'</span><span class="p">],</span> <span class="p">(</span><span class="s">'%H:%M:%S'</span><span class="p">))</span>
<span class="k">if</span> <span class="p">(</span><span class="n">datetime</span><span class="p">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">set_time</span><span class="p">).</span><span class="n">seconds</span> <span class="o">/</span> <span class="mi">60</span> <span class="o">&gt;=</span> <span class="mi">3</span><span class="p">:</span>
    <span class="bp">self</span><span class="p">.</span><span class="n">livedata_mini_chamber</span> <span class="o">=</span> <span class="bp">False</span>
</code></pre></div></div>

<p><img src="https://Yanghuiwon22.github.io/assets/img/feature-img/2024-08-20-1.png" /></p>
<p style="color: royalblue">'현재 실시간 데이터가 들어오고 있지 않다 : 보여지는 데이터는 과거의 데이터이다.'가 출력되고 있다</p>

<h3 id="데이터로드-시간을-출력">데이터로드 시간을 출력</h3>

<p>텍스트를 대시보드(회색컴퓨터)의 오른쪽 하단에 출력하기 위해서 텍스트 작업을 진행</p>

<p>텍스트를 파이게임 내에서 출력하기 위해서</p>
<ol>
  <li>text_surf  —&gt; 그리고자 하는 글자</li>
  <li>text_rect  —&gt; 글자를 담을 공간 <br />
위 두가지가 필요하다</li>
</ol>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">show_entry_updated_time</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text_surf</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'black'</span><span class="p">):</span>
    <span class="n">updateed_time_surf</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">font</span><span class="p">.</span><span class="n">render</span><span class="p">(</span><span class="n">text_surf</span><span class="p">,</span> <span class="bp">False</span><span class="p">,</span> <span class="n">color</span><span class="p">)</span>
    <span class="n">top</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">bottom</span> <span class="o">-</span> <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_height</span><span class="p">()</span> <span class="o">-</span> <span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="o">*</span><span class="mi">3</span>
    <span class="n">updated_time_rect</span> <span class="o">=</span> <span class="n">pygame</span><span class="p">.</span><span class="n">Rect</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">right</span><span class="o">-</span><span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_width</span><span class="p">()</span><span class="o">-</span><span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="o">*</span><span class="mi">3</span><span class="p">,</span> <span class="n">top</span><span class="p">,</span>
                                    <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_width</span><span class="p">(),</span> <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_height</span><span class="p">())</span>

    <span class="bp">self</span><span class="p">.</span><span class="n">updated_time_rect</span> <span class="o">=</span> <span class="n">updateed_time_surf</span><span class="p">.</span><span class="n">get_rect</span><span class="p">(</span><span class="n">center</span><span class="o">=</span><span class="p">(</span><span class="n">updated_time_rect</span><span class="p">.</span><span class="n">centerx</span><span class="p">,</span> <span class="n">updated_time_rect</span><span class="p">.</span><span class="n">centery</span><span class="p">))</span>
    <span class="bp">self</span><span class="p">.</span><span class="n">display_surface</span><span class="p">.</span><span class="n">blit</span><span class="p">(</span><span class="n">updateed_time_surf</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">updated_time_rect</span><span class="p">)</span>
</code></pre></div></div>

<p>위 코드에서 보면</p>
<ol>
  <li>text_surf로 그리고자하는 text를 받느다</li>
  <li>updateed_time_surf에 파이게임 내에서 사용할 수 있는데 텍스트의 형태로 변환한다</li>
  <li>text를 그리고자 하는 위치, 크기를 정한다</li>
  <li>text를 그리고자 하는 위치에 text를 그린다
의 순서로 되어있는 것을 확인할 수 있다.</li>
</ol>

<p>실시간 데이터를 받아오던 함수에서 return값을 리스트로 받아왔는데, 앞으로 리스트의 요소가 늘 것을 우려
그 경우, 프로그램 내에서 해당부분을 모두 수정해야 하므로 딕셔너리로 받아오도록 수정</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">player</span><span class="p">.</span><span class="n">pos_layer</span> <span class="o">==</span> <span class="s">'mini_chamber'</span><span class="p">:</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="p">.</span><span class="n">livedata_mini_chamber</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_updated_time</span><span class="p">(</span><span class="sa">f</span><span class="s">'UPDATED TIME : </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Date"</span><span class="p">]</span><span class="si">}</span><span class="s"> </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Time"</span><span class="p">]</span><span class="si">}</span><span class="s">'</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'red'</span><span class="p">)</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_fake</span><span class="p">(</span><span class="n">top</span><span class="o">=</span><span class="bp">self</span><span class="p">.</span><span class="n">bg_rect</span><span class="p">.</span><span class="n">bottom</span> <span class="o">+</span> <span class="bp">self</span><span class="p">.</span><span class="n">space</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">show_entry_updated_time</span><span class="p">(</span><span class="sa">f</span><span class="s">'UPDATED TIME : </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Date"</span><span class="p">]</span><span class="si">}</span><span class="s"> </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">get_data</span><span class="p">[</span><span class="s">"Time"</span><span class="p">]</span><span class="si">}</span><span class="s">'</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
</code></pre></div></div>
<p>앞에서 걸었던 조건에 방금 추가한 기능을 합쳐 코드를 작성하였다
실시간 데이터가 아닐 경우, 업데이트 시간을 빨간색으로 표시하여 사용자에게 알리도록 하였다.</p>

<p><img src="https://Yanghuiwon22.github.io/assets/img/feature-img/2024-08-20-2.png" /></p>
<p style="color: royalblue">데이터 로드 시간을 출력하고 있다</p>]]></content><author><name></name></author><category term="Demo" /><category term="chamber-sf" /><category term="pygame" /><summary type="html"><![CDATA[실시간 데이터가 들어오지 않을 시, 과거 데이터를 출력해준다.]]></summary></entry><entry><title type="html">깃허브 블로그 시작하기</title><link href="https://yanghuiwon22.github.io/demo/2024/06/26/%EA%B9%83%ED%97%88%EB%B8%8C%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0.html" rel="alternate" type="text/html" title="깃허브 블로그 시작하기" /><published>2024-06-26T00:00:00+00:00</published><updated>2024-06-26T00:00:00+00:00</updated><id>https://yanghuiwon22.github.io/demo/2024/06/26/%EA%B9%83%ED%97%88%EB%B8%8C%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</id><content type="html" xml:base="https://yanghuiwon22.github.io/demo/2024/06/26/%EA%B9%83%ED%97%88%EB%B8%8C%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0.html"><![CDATA[<p>원하는 블로그 테마를 fork하여 나의 블로그로 가져온다. <br />
config.yml파일의 url을 내 깃허브 블로그 주소로 수정한다.</p>

<p>❗❗ 사이트에 들어가보니 css가 깨진 것을 확인하였다 ❗❗
<img src="../assets/img/2024-06-26-css깨짐.png" /></p>

<p>이를 <code class="language-plaintext highlighter-rouge">baseurl : ""</code> 으로 수정하여 해결!</p>]]></content><author><name></name></author><category term="Demo" /><category term="github-blog" /><summary type="html"><![CDATA[원하는 블로그 테마를 fork하여 나의 블로그로 가져온다. config.yml파일의 url을 내 깃허브 블로그 주소로 수정한다.]]></summary></entry></feed>