<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>09LABS</title>
    <link>https://09labs.tistory.com/</link>
    <description>Embedded System Engineer
DevOps Engineer
Reverse Engineering</description>
    <language>ko</language>
    <pubDate>Thu, 9 Jul 2026 04:29:01 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Mcrane</managingEditor>
    <item>
      <title>[CAN Bus] 라즈베리파이로 CAN Bus를 해킹해보자</title>
      <link>https://09labs.tistory.com/64</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 재미난 프로젝트를 하나 진행하고 있다.&lt;br /&gt;취미로 하고있던 심레이싱에 기성품 핸들이 아니라 실제 차량의 핸들을 장착하고 싶어하는 동호회원이 꽤 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;959&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo0JAD/btsPFC2HMsm/0tFcO0tRHiVjbkZvMCZo41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo0JAD/btsPFC2HMsm/0tFcO0tRHiVjbkZvMCZo41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo0JAD/btsPFC2HMsm/0tFcO0tRHiVjbkZvMCZo41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo0JAD%2FbtsPFC2HMsm%2F0tFcO0tRHiVjbkZvMCZo41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;740&quot; data-origin-width=&quot;842&quot; data-origin-height=&quot;959&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에 포르쉐 911 핸들을 작업한 적이 있었는데 버튼을 하나 하나 납땜을 해야하다보니 굉장히 힘들었던 기억이 있다.&lt;br /&gt;조그 다이얼은 살리지 못했고 푸시버튼과 패들 쉬프트만 살릴 수 있었다. 제어보드도 에어백 커버 안에 넣다보니 배선이 굉장히 난잡해졌었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음은 벤츠 W212 핸들이었는데 SMD 택트 스위치라서 납땜이 불가하여 클락션과 패들 쉬프트만 살려서 보냈었다.&lt;br /&gt;그래서 생각을 해보니 여태 실패했던 이유가 CAN 신호를 취득하지 못하거나 저항값을 읽기가 매우 불편해서였는데 이번엔 CAN 신호를 사용하는 현대 차량의 핸들을 의뢰받았다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;핸들 모델과 회로도&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;747&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cpwqPb/btsPHmdOGkh/K3wLa8dYAkagpLzk9H1b5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cpwqPb/btsPHmdOGkh/K3wLa8dYAkagpLzk9H1b5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cpwqPb/btsPHmdOGkh/K3wLa8dYAkagpLzk9H1b5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcpwqPb%2FbtsPHmdOGkh%2FK3wLa8dYAkagpLzk9H1b5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;379&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;747&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 타자는 GV80 럭비공 핸들이다. 에어백 커버가 큼직해서 내부 공간도 여유가 많고 무엇보다 B-CAN 신호를 취득할 수 있도록 되어있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;1314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctbG8V/btsPHlsqm2G/aUeqrii5ssp1HLQnFpXsiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctbG8V/btsPHlsqm2G/aUeqrii5ssp1HLQnFpXsiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctbG8V/btsPHlsqm2G/aUeqrii5ssp1HLQnFpXsiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctbG8V%2FbtsPHlsqm2G%2FaUeqrii5ssp1HLQnFpXsiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1836&quot; height=&quot;1314&quot; data-origin-width=&quot;1836&quot; data-origin-height=&quot;1314&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회로도도 생각보다 간단했다. 상시전원에 12V 연결해주고 접지만 잡아준 뒤 B-CAN 신호만 받아오면 된다.&lt;br /&gt;특이하게도 우측 리모콘 어셈블리가 좌측 신호와 패들시프트 신호까지 한꺼번에 처리하도록 회로가 구성되어 있다.&lt;br /&gt;추가적으로 햅틱 모듈 (작은 모터)가 하나 있는데 이 기능도 살릴 수 있을 것 같았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ptYpm/btsPGuDbCFk/Gzki0dxjizg2OJ5txD9MsK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ptYpm/btsPGuDbCFk/Gzki0dxjizg2OJ5txD9MsK/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ptYpm/btsPGuDbCFk/Gzki0dxjizg2OJ5txD9MsK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FptYpm%2FbtsPGuDbCFk%2FGzki0dxjizg2OJ5txD9MsK%2Fimg.webp&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;366&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 타자는 아이오닉 5N이다. 요즘 아이오닉 5에 이 핸들을 이식하거나 타 차량에도 이식하는 후기가 꽤 많이 보였다.&lt;br /&gt;핸들만 대략 40~60만원 선으로 저렴한 편은 아니었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2025&quot; data-origin-height=&quot;1451&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNk0Ps/btsPGuDbCGQ/Nc7wlnp2pvNwLhmA7HgQr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNk0Ps/btsPGuDbCGQ/Nc7wlnp2pvNwLhmA7HgQr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNk0Ps/btsPGuDbCGQ/Nc7wlnp2pvNwLhmA7HgQr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNk0Ps%2FbtsPGuDbCGQ%2FNc7wlnp2pvNwLhmA7HgQr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2025&quot; height=&quot;1451&quot; data-origin-width=&quot;2025&quot; data-origin-height=&quot;1451&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이오닉 5N도 B-CAN을 사용한다. 다만 B2-CAN HS로 되어있는거로 봐서 CAN-FD일 가능성도 있었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;부품 선정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. CAN Module&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pcmDZ/btsPF7VK7fL/ceh8MLh8kNv5yMsFGAcCi0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pcmDZ/btsPF7VK7fL/ceh8MLh8kNv5yMsFGAcCi0/img.jpg&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot; data-is-animation=&quot;false&quot; width=&quot;650&quot; height=&quot;650&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pcmDZ/btsPF7VK7fL/ceh8MLh8kNv5yMsFGAcCi0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpcmDZ%2FbtsPF7VK7fL%2Fceh8MLh8kNv5yMsFGAcCi0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VmSIc/btsPDrauNVi/InKR4yvqSRbp9juHzJmZ1k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VmSIc/btsPDrauNVi/InKR4yvqSRbp9juHzJmZ1k/img.jpg&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VmSIc/btsPDrauNVi/InKR4yvqSRbp9juHzJmZ1k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVmSIc%2FbtsPDrauNVi%2FInKR4yvqSRbp9juHzJmZ1k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 간단히 테스트만 해보기 위해 MCP2515 CAN Module을 구매했다. SPI 인터페이스를 지원하고 1Mbps까지 지원한다.&lt;br /&gt;만약 CAN-FD를 테스트하려면 MCP2518 모듈을 구매해야한다. SN65HVD230은 TTL 인터페이스를 지원하고 모듈 사이즈가 작아서 임시로 2개 구매해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. nRF24L01&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mUMRh/btsPDWH7FmK/TOdiLmjvrLHAjIQtG29r4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mUMRh/btsPDWH7FmK/TOdiLmjvrLHAjIQtG29r4K/img.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;800&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;39.98&quot; style=&quot;width: 39.5112%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mUMRh/btsPDWH7FmK/TOdiLmjvrLHAjIQtG29r4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmUMRh%2FbtsPDWH7FmK%2FTOdiLmjvrLHAjIQtG29r4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;800&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y63MT/btsPERzje9h/oEWnaI9oeOVN9veYtBS3N1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y63MT/btsPERzje9h/oEWnaI9oeOVN9veYtBS3N1/img.jpg&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;666&quot; data-is-animation=&quot;false&quot; style=&quot;width: 59.3261%;&quot; data-widthpercent=&quot;60.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y63MT/btsPERzje9h/oEWnaI9oeOVN9veYtBS3N1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY63MT%2FbtsPERzje9h%2FoEWnaI9oeOVN9veYtBS3N1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nRF24L01은 SIMAGIC 휠베이스와 통신하기 위해서 구매했다. 우선 왼쪽 모듈로 테스트해보고 공간이 부족하면 우측 모듈로 교체 예정이다. SIMAGIC 휠베이스는 2.4Ghz 대역으로 통신을 하며 위 모듈로 통신이 가능하다는 Git Repository를 하나 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Kegetys/simagic-arduino-poc&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Kegetys/simagic-arduino-poc&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754239926544&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Kegetys/simagic-arduino-poc: Simagic Alpha wireless protocol description and proof-of-concept Arduino code&quot; data-og-description=&quot;Simagic Alpha wireless protocol description and proof-of-concept Arduino code - Kegetys/simagic-arduino-poc&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Kegetys/simagic-arduino-poc&quot; data-og-url=&quot;https://github.com/Kegetys/simagic-arduino-poc&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bK0lKR/hyZuBZJJWS/iKi6AfrKWaKePn7YGHMKUK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/dfu0GS/hyZuEWsJkS/iEu5EPY0cwNqzcElP0V360/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/Kegetys/simagic-arduino-poc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Kegetys/simagic-arduino-poc&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bK0lKR/hyZuBZJJWS/iKi6AfrKWaKePn7YGHMKUK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/dfu0GS/hyZuEWsJkS/iEu5EPY0cwNqzcElP0V360/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - Kegetys/simagic-arduino-poc: Simagic Alpha wireless protocol description and proof-of-concept Arduino code&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Simagic Alpha wireless protocol description and proof-of-concept Arduino code - Kegetys/simagic-arduino-poc&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Boost 컨버터&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QSaLJ/btsPE2Osg9r/BhBMhgOKRctKsvJGdLrYt0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QSaLJ/btsPE2Osg9r/BhBMhgOKRctKsvJGdLrYt0/img.jpg&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;550&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.0884%; margin-right: 10px;&quot; data-widthpercent=&quot;49.67&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QSaLJ/btsPE2Osg9r/BhBMhgOKRctKsvJGdLrYt0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQSaLJ%2FbtsPE2Osg9r%2FBhBMhgOKRctKsvJGdLrYt0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F6OLj/btsPFEfaZzr/zdGLebgsfT7CgGz8KuLZZK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F6OLj/btsPFEfaZzr/zdGLebgsfT7CgGz8KuLZZK/img.jpg&quot; data-origin-width=&quot;226&quot; data-origin-height=&quot;223&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.7488%;&quot; data-widthpercent=&quot;50.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F6OLj/btsPFEfaZzr/zdGLebgsfT7CgGz8KuLZZK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF6OLj%2FbtsPFEfaZzr%2FzdGLebgsfT7CgGz8KuLZZK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;226&quot; height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MT3608은 저렴하면서도 꽤 많이 사용되는 모듈이다. 다만.... 고장이 잘 난다. 우측 모듈은 아마 같은 칩을 사용할텐데 신뢰성이 괜찮았었다. 우선 MT3608은 임시로 사용할 예정이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;라즈베리파이 배선&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XUzyj/btsPGj9uNqe/rX8RkIH4Ah5tCcSKc5RcVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XUzyj/btsPGj9uNqe/rX8RkIH4Ah5tCcSKc5RcVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XUzyj/btsPGj9uNqe/rX8RkIH4Ah5tCcSKc5RcVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXUzyj%2FbtsPGj9uNqe%2FrX8RkIH4Ah5tCcSKc5RcVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;768&quot; height=&quot;512&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mwcLt/btsPEp4mGqI/ui5GhqKgrMQm6HXgoSj8K1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mwcLt/btsPEp4mGqI/ui5GhqKgrMQm6HXgoSj8K1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mwcLt/btsPEp4mGqI/ui5GhqKgrMQm6HXgoSj8K1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmwcLt%2FbtsPEp4mGqI%2Fui5GhqKgrMQm6HXgoSj8K1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1000&quot; height=&quot;559&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 MCP2515 모듈로 테스트를 진행하기 위해서 위 회로도를 사용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1754240153043&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GPIO                CAN
HEADR   SIGNAL     MODULE
PIN      NAME  --- SIGNAL
#01       3,3V --- VCC
#02         5V --- Extra wire to Vcc TJA1050
#06        GND --- GND
#09        GND --- GND to CAN BUS (there is no GND terminal on CAN MODULE)
#19       MOSI --- SI
#21       MISO --- SO
#23       SCLK --- SCK/CLK
#24   SPI0.CE0 --- CS&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라즈베리파이와 CAN 모듈은 위와 같이 연결을 해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;749&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zsure/btsPFB3QexQ/eF4i9Tj2m7uiEuz21NDZN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zsure/btsPFB3QexQ/eF4i9Tj2m7uiEuz21NDZN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zsure/btsPFB3QexQ/eF4i9Tj2m7uiEuz21NDZN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZsure%2FbtsPFB3QexQ%2FeF4i9Tj2m7uiEuz21NDZN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1117&quot; height=&quot;749&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;749&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GV80의 클락 스프링 커넥터를 정면에서 바라본 핀 배열은 위와 같다.&lt;br /&gt;전원부와 B-CAN만 취득하면 되니 7, 8, 13, 14번만 우선 사용한다.&lt;br /&gt;7번은 파워써플라이를 사용해서 12V를 공급해줬다. 접지는 라즈베리파이 접지와 같이 연결을 해주었다.&lt;br /&gt;핸들 접지와 라즈베리파이 접지를 연결하는 이유는 CAN 신호가 이상하게 들어올 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250804_015938756.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bly1GQ/btsPEt6LaDi/6WJ5lDf8usnozNNRrPEnC1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bly1GQ/btsPEt6LaDi/6WJ5lDf8usnozNNRrPEnC1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bly1GQ/btsPEt6LaDi/6WJ5lDf8usnozNNRrPEnC1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbly1GQ%2FbtsPEt6LaDi%2F6WJ5lDf8usnozNNRrPEnC1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250804_015938756.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커넥터에는 위와 같이 점퍼 케이블을 연결해서 전원과 MCP2515 CAN 모듈에 연결해줬다.&lt;/p&gt;
&lt;pre id=&quot;code_1754240478964&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# /boot/firmware/config.txt
dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=12
dtoverlay=spi-bcm2835-overlay&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 라즈베리파이에 위 내용을 &lt;b&gt;/boot/firmware/config.txt&lt;/b&gt;에 입력해준 뒤 재부팅을 했. (# 내용은 제외)&lt;/p&gt;
&lt;pre id=&quot;code_1754240591997&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo apt-get update
$ sudo apt-get install can-utils&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 CAN utility를 설치해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1754240632463&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ls /sys/bus/spi/devices/spi0.0
driver  modalias  net  of_node  subsystem  uevent
$ ls /sys/bus/spi/devices/spi0.0/net
can0
$ ls /sys/bus/spi/devices/spi0.0
driver  modalias  net  of_node  subsystem  uevent
$ ls /sys/bus/spi/devices/spi0.0/net/
can0
$ ls /sys/bus/spi/devices/spi0.0/net/can0/
addr_assign_type  carrier_changes  duplex             iflink            operstate       speed         uevent
address           device           flags              link_mode         phys_port_id    statistics
addr_len          dev_id           gro_flush_timeout  mtu               phys_port_name  subsystem
broadcast         dev_port         ifalias            name_assign_type  phys_switch_id  tx_queue_len
carrier           dormant          ifindex            netdev_group      queues          type&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dtoverlay 설정과 can-utils까지 설치가 완료되면 위와 같이 SPI 0.0 드라이버에 CAN0가 인식되는 것을 알 수 있다.&lt;br /&gt;CAN 드라이버는 socketcan으로 작동하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1754240724114&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo ip link set can0 up type can bitrate 500000&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 현대차는 500000 bitrate를 사용한다. 위와 같이 입력을 해주면 socketcan이 활성화된다.&lt;/p&gt;
&lt;pre id=&quot;code_1754240806794&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;can0: flags=193&amp;lt;UP,RUNNING,NOARP&amp;gt;  mtu 16
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
        RX packets 130173  bytes 1041384 (1016.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 460  bytes 3680 (3.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4099&amp;lt;UP,BROADCAST,MULTICAST&amp;gt;  mtu 1500
        ether 1c:16:12:1e:10:11  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73&amp;lt;UP,LOOPBACK,RUNNING&amp;gt;  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10&amp;lt;host&amp;gt;
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 112  bytes 10746 (10.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 112  bytes 10746 (10.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 can0가 인식되면 기본 준비는 마무리 된 것이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Python 및 모듈 설치&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 python은 pip로 모듈을 설치하면 global로 설치가 되지 않고 경고를 내뿜는다. 따라서 venv로 진행을 하는 것을 권장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1754240963041&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ python3 -m venv .venv
$ source .venv/bin/activate
(.venv) $ pip3 install python-can&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 입력을 해주면 venv가 활성화된다. 그 다음 python-can 모듈을 설치해줬다.&lt;br /&gt;요즘 또 대세는 ChatGPT로 바이브 코딩을 하는 것이지 않나 생각이 되기도 하고 CAN 신호 변화를 자세히 관찰하기 위해서 몇 가지 조건을 추가해서 코드를 만들었다.&lt;/p&gt;
&lt;pre id=&quot;code_1754241106962&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import can
import threading
import time
import curses

INTERFACE = 'can0'
TESTER_PRESENT_INTERVAL = 5  # seconds
TESTER_PRESENT_ID = 0x7DF
TESTER_PRESENT_DATA = [0x02, 0x3E, 0x00] + [0xAA] * 5

# Shared state
last_messages = {}
lock = threading.Lock()

def send_tester_present(bus):
    msg = can.Message(
        arbitration_id=TESTER_PRESENT_ID,
        data=TESTER_PRESENT_DATA,
        is_extended_id=False
    )
    while True:
        try:
            bus.send(msg)
        except can.CanError:
            pass
        time.sleep(TESTER_PRESENT_INTERVAL)

def receive_messages(bus):
    while True:
        msg = bus.recv(timeout=1.0)
        if msg:
            with lock:
                last_messages[msg.arbitration_id] = (msg.data, time.time())

def curses_display(stdscr):
    curses.start_color()
    curses.use_default_colors()
    curses.init_pair(1, curses.COLOR_GREEN, -1)
    curses.init_pair(2, curses.COLOR_RED, -1)

    stdscr.nodelay(True)
    prev_values = {}

    while True:
        stdscr.clear()
        stdscr.addstr(0, 2, &quot;CAN Monitor (Change Highlight)&quot;, curses.A_BOLD)
        stdscr.addstr(1, 0, &quot;Time      ID     Data&quot;)

        with lock:
            sorted_ids = sorted(last_messages.keys())

        for idx, msg_id in enumerate(sorted_ids, start=2):
            with lock:
                data, timestamp = last_messages[msg_id]
            time_str = time.strftime(&quot;%H:%M:%S&quot;, time.localtime(timestamp))
            stdscr.addstr(idx, 0, f&quot;{time_str}  0x{msg_id:03X}  &quot;)

            prev_data = prev_values.get(msg_id, None)
            for i, byte in enumerate(data):
                if prev_data and i &amp;lt; len(prev_data) and byte != prev_data[i]:
                    stdscr.addstr(f&quot;{byte:02X} &quot;, curses.color_pair(2))  # red
                else:
                    stdscr.addstr(f&quot;{byte:02X} &quot;, curses.color_pair(1))  # green

            prev_values[msg_id] = data

        stdscr.refresh()
        time.sleep(0.1)

def main():
    bus = can.interface.Bus(channel=INTERFACE, bustype='socketcan')

    t1 = threading.Thread(target=send_tester_present, args=(bus,), daemon=True)
    t2 = threading.Thread(target=receive_messages, args=(bus,), daemon=True)

    t1.start()
    t2.start()

    curses.wrapper(curses_display)

if __name__ == &quot;__main__&quot;:
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 가장 중요한 부분은 UDS 패킷인데 Tester Present 패킷을 전송하지 않으면 핸들의 CAN 모듈이 슬립모드에 들어가는 것을 알아냈다. 아무 패킷이나 전송하면 잠깐 깨어났다가 8초 정도 후에 슬립모드에 들어간다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

            &lt;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&gt;
            &lt;/figure&gt;
        
&lt;p data-ke-size=&quot;size16&quot;&gt;영상을 보면 0x1CF 패킷의 4번째 바이트가 20에서 28로 변화하는 것을 볼 수 있다.&lt;br /&gt;그 다음 0x448과 0x4D5 패킷이 변화하는 것을 볼 수 있었다. 핸즈프리 버튼과 모드 버튼, 메뉴 버튼, LKAS 버튼은 0x448을 사용하고 볼륨 다이얼과 상, 하, OK 버튼은 0x448과 0x4D5에 모두 노출이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 취득한 CAN 신호로 펌웨어만 만들면 될 것 같다.&lt;br /&gt;다음 포스팅은 nRF24L01을 사용해서 SIMAGIC 휠베이스에 버튼 신호를 전송해 보는 것을 작성할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘의 삽질 끝!&lt;/p&gt;</description>
      <category>Linux/Raspberry Pi</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/64</guid>
      <comments>https://09labs.tistory.com/64#entry64comment</comments>
      <pubDate>Mon, 4 Aug 2025 02:21:59 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 라즈베리파이에 Nginx Proxy Manager를 설치해보자</title>
      <link>https://09labs.tistory.com/62</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;홈 서버를 운영하면서 한가지 불안한 점이 있었다.&lt;br /&gt;공유기를 타고 바로 내 홈서버에 접속이 가능하다는 점이었는데 포트포워딩으로 일부 포트만 열어둬서 찝찝함이 없지않아 있다.&lt;br /&gt;예전에 라즈베리파이를 공유기에 꽂아놓고 포트를 전부 개방했다가 해킹당해서 라즈베리파이를 포맷하게 된 적이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 그 때 라즈베리파이의 비밀번호를 변경하지 않았던 탓도 있었다.&lt;br /&gt;다행히 최근에는 Raspberry Pi Imager에 사용자 계정을 커스텀으로 설정할 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 홈서버를 보호하고자 직장 동료에게 물어보니 성능이 그렇게 좋지 않은 라즈베리파이로 Reverse Proxy 역할을 하게 해주면 안전하게 기기를 관리할 수 있게 된다고 들었다.&lt;br /&gt;그럼 Proxy와 Reverse Proxy의 차이는 뭘까?&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Proxy? Reverse Proxy?&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/04hJO/btsOMaZ7GdK/sFkukGk2PPOC2lrCwmf900/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/04hJO/btsOMaZ7GdK/sFkukGk2PPOC2lrCwmf900/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/04hJO/btsOMaZ7GdK/sFkukGk2PPOC2lrCwmf900/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F04hJO%2FbtsOMaZ7GdK%2FsFkukGk2PPOC2lrCwmf900%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;600&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림에서 가장 큰 차이점은 Proxy 서버가 클라이언트쪽에 있거나, 서버쪽에 있는 것에 따라 Forward Proxy, Reverse Proxy로 나뉜다.&lt;br /&gt;Forwared Proxy 서버는 캐싱을 통해 부하를 줄이는 효과도 줄 수 있으며 클라이언트측 보안을 위해서 사용할 수 있다.&lt;br /&gt;간단한 예로 사내망의 클라이언트가 인터넷에 접속을 할 때 Forward Proxy에 Rule을 추가하면 유해 사이트 접속을 차단할 수 있다.&lt;br /&gt;&lt;s&gt;집에 Forward Proxy를 두면 불법 토토를 방지...&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reverse Proxy는 Forward Proxy와 반대로 서버 보안, 로드밸런싱, 캐싱을 목적으로 사용할 수 있다.&lt;br /&gt;로드밸런싱은 서버의 과도한 트래픽 유입이 방지하기 위해 여러 대의 Reverse Proxy를 서버 앞단에 둘 수 있다.&lt;br /&gt;물론 작고 귀여운 홈서버에는 로드밸런싱이 굳이 필요하진 않겠지만 해커들의 무작위 공격을 방지할 수도 있다. (이상한 패턴 감지)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 보안 측면에서는 클라이언트가 접근하고자 하는 서버의 정보를 숨기는 역할을 한다.&lt;br /&gt;클라이언트는 서버로 접속할 때 Reverse Proxy의 URL로 접속하기 때문에 서버의 정보를 알지 못한 채 서비스를 이용하게 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Nginx on Raspberry Pi&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 작고 강력한 킹갓 라즈베리파이는 작고 소중한 홈서버를 보호할 리버스 프록시 서버의 역할로는 충분하다.&lt;br /&gt;보통 Nginx는 웹서버로 흔히들 알고있다. 물론 정적 웹서버를 아주 간단하게 띄울 수 있으니 유용하게 사용한다.&lt;br /&gt;하지만 Nginx에 기능만 활성화 시키면 Proxy 서버로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다들 Nginx를 CLI로 설치하고 나서 가장 당황하는 것이 conf 파일을 수정하는 것인데 이게 상당히 귀찮다...&lt;br /&gt;요즘은 Nginx UI, Nginx Proxy Manager와 같은 GUI 툴이 있어서 관리와 설정을 쉽게 반영할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfIKch/btsOMqhl9Uv/gXnZlNjrJKNVlE743NUUm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfIKch/btsOMqhl9Uv/gXnZlNjrJKNVlE743NUUm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfIKch/btsOMqhl9Uv/gXnZlNjrJKNVlE743NUUm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfIKch%2FbtsOMqhl9Uv%2FgXnZlNjrJKNVlE743NUUm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;816&quot; height=&quot;445&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx Proxy Manager는 Docker에 설치하는 것이기 때문에 리소스가 부족하지 않을까 걱정했다.&lt;br /&gt;ChatGPT에게 질문해본 결과 충분히 3B+ 모델에서도 감당이 가능하고 인터페이스나 커뮤니티 지원도 훨씬 좋다는 피드백을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;준비물&lt;br /&gt;&lt;/b&gt;- 라즈베리파이 (최소 3B 이상 권장)&lt;br /&gt;- 충전기 (5V 2.5A 이상 권장)&lt;br /&gt;- 랜선&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. Raspbian 설치&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://www.raspberrypi.com/software/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.raspberrypi.com/software/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1750430749496&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Raspberry Pi OS &amp;ndash; Raspberry Pi&quot; data-og-description=&quot;From industries large and small, to the kitchen table tinkerer, to the classroom coder, we make computing accessible and affordable for everybody.&quot; data-og-host=&quot;www.raspberrypi.com&quot; data-og-source-url=&quot;https://www.raspberrypi.com/software/&quot; data-og-url=&quot;https://www.raspberrypi.com/software/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/o8rcD/hyZbDwQoWy/SdQ1MY2z4xA1NfygvrEoB1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/7Y5ol/hyZbqRNvI3/lUBZCnk2h8tljdTKyTqb9k/img.png?width=1500&amp;amp;height=1200&amp;amp;face=0_0_1500_1200,https://scrap.kakaocdn.net/dn/bRuCq7/hyZbus8bYX/aAruBKLGK6KvZs08hr595K/img.png?width=900&amp;amp;height=700&amp;amp;face=0_0_900_700&quot;&gt;&lt;a href=&quot;https://www.raspberrypi.com/software/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.raspberrypi.com/software/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/o8rcD/hyZbDwQoWy/SdQ1MY2z4xA1NfygvrEoB1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/7Y5ol/hyZbqRNvI3/lUBZCnk2h8tljdTKyTqb9k/img.png?width=1500&amp;amp;height=1200&amp;amp;face=0_0_1500_1200,https://scrap.kakaocdn.net/dn/bRuCq7/hyZbus8bYX/aAruBKLGK6KvZs08hr595K/img.png?width=900&amp;amp;height=700&amp;amp;face=0_0_900_700');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Raspberry Pi OS &amp;ndash; Raspberry Pi&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;From industries large and small, to the kitchen table tinkerer, to the classroom coder, we make computing accessible and affordable for everybody.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.raspberrypi.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 위 페이지에 접속해서 Raspberry Pi Imager를 다운로드 받는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cA79q5/btsOMdvOsi5/h5Qtm2QBZPCuSDKyQcvsP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cA79q5/btsOMdvOsi5/h5Qtm2QBZPCuSDKyQcvsP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cA79q5/btsOMdvOsi5/h5Qtm2QBZPCuSDKyQcvsP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcA79q5%2FbtsOMdvOsi5%2Fh5Qtm2QBZPCuSDKyQcvsP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;675&quot; height=&quot;474&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라즈베리파이 3B를 사용할 경우 OS는 필히 Lite 버전을 설치하는 것을 권장한다.&lt;br /&gt;Desktop 버전을 설치했다가 바탕화면에서 멈춰있는 경험을 했다...&lt;br /&gt;4B 이상은 Desktop 버전을 설치해도 괜찮으나 굳이 리버스 프록시 서버에 Desktop 버전을 설치할 필요는 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;431&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7LsPC/btsOMoqir8S/5Tm0QeuamoiKSwieq5czT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7LsPC/btsOMoqir8S/5Tm0QeuamoiKSwieq5czT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7LsPC/btsOMoqir8S/5Tm0QeuamoiKSwieq5czT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7LsPC%2FbtsOMoqir8S%2F5Tm0QeuamoiKSwieq5czT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;431&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;431&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SD카드에 OS 설치가 완료되면 언마운트 했다가 다시 마운트하고 SD카드에 ssh라는 빈 파일을 하나 만든다.&lt;br /&gt;SD카드의 경로가 F:\ 라면 F:\ssh 와 같이 생성하면 된다. VS Code나 Notepad++와 같은 편집기를 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. apt upgrade &amp;amp; Docker 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750431084434&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo apt-get update
$ sudo apt-get upgrade -y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS 설치를 완료한 뒤 부팅이 완료되면 위와 같이 입력해서 모든 패키지를 새 버전으로 업데이트 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1750431801634&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl -fsSL get.docker.com -o get-docker.sh &amp;amp;&amp;amp; sh get-docker.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 위 명령어를 입력하면 라즈베리파이에 Docker engine이 설치된다.&lt;/p&gt;
&lt;pre id=&quot;code_1750431946943&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo gpasswd -a pi docker&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Group에 사용자 계정을 추가한다.&lt;br /&gt;pi는 기본 사용자명이기 때문에 만약 Rasbperry Pi Imager에서 계정명을 변경했으면 해당 계정 이름을 입력하면 된다.&lt;br /&gt;위 명령어 실행 후 재시작하면 docker 명령어를 사용할 수 있게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1750432121784&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo apt-get install -y python3-full python3-pip&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Docker Compose를 설치하기 전 Python3와 pip를 설치해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1750432158694&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo apt-get install -y docker-compose&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어를 입력해서 Docker Compose를 설치한다.&lt;br /&gt;Docker Compose는 여러 개의 컨테이너를 하나의 서비스로 정의해서 관리할 수 있는 도구이다.&lt;br /&gt;Docker 명령어로 여러 개의 컨테이너를 띄우려면 docker run 명령어를 사용해서 컨테이너를 하나씩 실행해야 하지만 Docker Compose를 사용하면 YAML로 정의된 Manifest에 서비스와 컨테이너를 정의하고 docker-compose 명령 한 번으로 컨테이너 여러 개를 한 번에 실행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Nginx Proxy Manager 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750432782673&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo mkdir -p /opt/stacks/nginxproxymanager
$ cd /opt/stacks/nginxproxymanager&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Compose까지 설치가 완료되면 위 명령어를 입력해서 Nginx Proxy Manager의 데이터를 기록할 폴더를 생성한다.&lt;/p&gt;
&lt;pre id=&quot;code_1750433007573&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo nano compose.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 YAML 파일을 작성할 수 있도록 nano 편집기로 파일을 연다.&lt;/p&gt;
&lt;pre id=&quot;code_1750432645094&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      # These ports are in format &amp;lt;host-port&amp;gt;:&amp;lt;container-port&amp;gt;
      - '80:80' # Public HTTP Port
      - '443:443' # Public HTTPS Port
      - '81:81' # Admin Web Port
      # Add any other Stream port you want to expose
      # - '21:21' # FTP
    environment:
      # Mysql/Maria connection parameters:
      DB_MYSQL_HOST: &quot;db&quot;
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: &quot;npm&quot;
      DB_MYSQL_PASSWORD: &quot;npm&quot;
      DB_MYSQL_NAME: &quot;npm&quot;
      # Uncomment this if IPv6 is not enabled on your host
      # DISABLE_IPV6: 'true'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    depends_on:
      - db

  db:
    image: 'yobasystems/alpine-mariadb:latest'
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: 'npm'
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npm'
      MYSQL_PASSWORD: 'npm'
      MARIADB_AUTO_UPGRADE: '1'
    volumes:
      - ./mysql:/var/lib/mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 YAML 매니페스트를 작성 후 ctrl+x키 입력 후 엔터를 치면 nano 편집기가 종료되며 내용이 파일에 기록된다.&lt;/p&gt;
&lt;pre id=&quot;code_1750434176844&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker compose up -d
[+] Running 36/41
 ⠏ app [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 262.1MB / 338.3MB Pulling                                                                                                                      127.9s 
   ✔ b47565bb13c5 Pull complete                                                                                                                                                              44.4s 
   ✔ 80ee10acd8e3 Pull complete                                                                                                                                                              45.5s 
   ✔ 3d54d5509f0a Pull complete                                                                                                                                                              81.5s 
   ✔ d0befc9d6b42 Pull complete                                                                                                                                                              82.7s 
   ✔ 19e2e7931fb8 Pull complete                                                                                                                                                              84.9s 
   ✔ c223caf066db Pull complete                                                                                                                                                              88.6s 
   ✔ 3747cfb47804 Pull complete                                                                                                                                                              89.5s 
   ⠏ 19c59b2f76d0 Extracting      [=======================================&amp;gt;           ]  35.32MB/45.19MB                                                                                    123.9s 
   ✔ f2c83aa05d1a Download complete                                                                                                                                                          28.7s 
   ✔ 23c413e9ce10 Download complete                                                                                                                                                          29.6s 
   ✔ 18f9bb6dfe42 Download complete
   [+] Running 3/3
 ✔ Network nginxproxymanager_default  Created                                                                                                                                                 0.6s 
 ✔ Container nginxproxymanager-db-1   Started                                                                                                                                                 3.6s 
 ✔ Container nginxproxymanager-app-1  Started&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 드디어 Nginx Proxy Manager를 실행시켜볼 차례이다.&lt;br /&gt;위와 같이 docker compose up -d 명령어를 입력하면 Docker Image를 다운로드 하고 서비스에 정의된 컨테이너가 실행된다.&lt;/p&gt;
&lt;pre id=&quot;code_1750434645934&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ hostname -I
192.168.0.2 172.17.0.1 172.18.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라즈베리파이 IP 주소는 위 명령어로 확인할 수 있다.&lt;br /&gt;일반적으로 공유기에 연결되어 있으면 192.168로 시작하는 주소를 볼 수 있다. (공유기마다 살짝 다를 수 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 PC에서 웹브라우저를 켠 뒤 &lt;b&gt;http://&amp;lt;IP주소&amp;gt;:81/&lt;/b&gt;과 같이 입력하면 Nginx Proxy Manager 페이지로 접속할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Nginx Proxy Manager 초기 설정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/weMsz/btsOKqJ1vGN/8eXBywwUJCkqvepfkfKEQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/weMsz/btsOKqJ1vGN/8eXBywwUJCkqvepfkfKEQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/weMsz/btsOKqJ1vGN/8eXBywwUJCkqvepfkfKEQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FweMsz%2FbtsOKqJ1vGN%2F8eXBywwUJCkqvepfkfKEQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1247&quot; height=&quot;704&quot; data-origin-width=&quot;1247&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ID : admin@example.com&lt;br /&gt;Password : changeme&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nginx Proxy Manager에 접속해서 초기 계정과 비밀번호를 입력한 뒤 로그인 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;745&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZM7gx/btsOKrWr7xP/vbsRRjwZPS3l9Zktpuz9SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZM7gx/btsOKrWr7xP/vbsRRjwZPS3l9Zktpuz9SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZM7gx/btsOKrWr7xP/vbsRRjwZPS3l9Zktpuz9SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZM7gx%2FbtsOKrWr7xP%2FvbsRRjwZPS3l9Zktpuz9SK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1276&quot; height=&quot;745&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;745&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인을 완료하면 위와 같이 이메일과 사용자 정보를 변경하라고 한다.&lt;br /&gt;기본값을 놔두면 보안에 취약하므로 변경한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;746&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kWXkg/btsOLBxgJ6Q/n1d4gUTYUWw7uy96WDdrx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kWXkg/btsOLBxgJ6Q/n1d4gUTYUWw7uy96WDdrx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kWXkg/btsOLBxgJ6Q/n1d4gUTYUWw7uy96WDdrx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkWXkg%2FbtsOLBxgJ6Q%2Fn1d4gUTYUWw7uy96WDdrx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1273&quot; height=&quot;746&quot; data-origin-width=&quot;1273&quot; data-origin-height=&quot;746&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계정을 변경하면 비밀번호도 변경하라고 나온다.&lt;br /&gt;비밀번호도 변경 후 Save 버튼을 눌러준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Proxy Host 추가&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;678&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cP15va/btsOL9GX07v/n0wtKdqwm8KumM5D52j380/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cP15va/btsOL9GX07v/n0wtKdqwm8KumM5D52j380/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cP15va/btsOL9GX07v/n0wtKdqwm8KumM5D52j380/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcP15va%2FbtsOL9GX07v%2Fn0wtKdqwm8KumM5D52j380%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;678&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Reverse Proxy 역할을 할 수 있도록 Proxy Host를 추가한다.&lt;br /&gt;상단 메뉴에서 Hosts를 누르면 Proxy Host를 추가할 수 있다.&lt;br /&gt;Add Proxy Host를 눌러서 새 프록시 호스트를 추가한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUZyhl/btsOKlhWRio/I7ku7CRZnq9UXLohpMcNUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUZyhl/btsOKlhWRio/I7ku7CRZnq9UXLohpMcNUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUZyhl/btsOKlhWRio/I7ku7CRZnq9UXLohpMcNUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUZyhl%2FbtsOKlhWRio%2FI7ku7CRZnq9UXLohpMcNUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;534&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요에 따라 기능은 켜고 끄면 된다. 일반적으로 다 켜는 것을 권장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Domain Names : 인입될 도메인 (여러 개 추가 가능)&lt;br /&gt;Forward Hostname / IP : 대상 서버 도메인 또는 IP주소&lt;br /&gt;Forward Port : 서비스 포트 (서버 포트)&lt;br /&gt;Cache Assets : 정적 콘텐츠 캐싱&lt;br /&gt;Block Common Exploits : 공격 패턴 차단, SQL Injection 차단 기능&lt;br /&gt;WebSocket Support : 웹소켓 지원&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1263&quot; data-origin-height=&quot;434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tFVJo/btsOKoZZuBM/A2VVhqqyqkqjKXpC9BrSk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tFVJo/btsOKoZZuBM/A2VVhqqyqkqjKXpC9BrSk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tFVJo/btsOKoZZuBM/A2VVhqqyqkqjKXpC9BrSk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtFVJo%2FbtsOKoZZuBM%2FA2VVhqqyqkqjKXpC9BrSk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1263&quot; height=&quot;434&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1263&quot; data-origin-height=&quot;434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Proxy Host를 추가하면 위와 같이 추가된 호스트 정보를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Ingress 설정을 반영해서 Sub Path로 Grafana Dashboard에 접근해보자.&lt;br /&gt;원래는 클라이언트 -&amp;gt; 공유기 포트포워딩 -&amp;gt; NAS 서버 -&amp;gt; k3d Container -&amp;gt; Ingress Nginx -&amp;gt; Application 순서로 접속했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reverse Proxy가 NAS 서버 앞단에서 프록시 역할을 해주므로 아래와 같이 접속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 -&amp;gt; 공유기 -&amp;gt; Reverse Proxy -&amp;gt; NAS 서버 -&amp;gt; k3d Container -&amp;gt; Ingress Nginx -&amp;gt; Application&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;1057&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUBlFX/btsOLze6pg7/6rMzX8QseKlX2OYJotuSFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUBlFX/btsOLze6pg7/6rMzX8QseKlX2OYJotuSFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUBlFX/btsOLze6pg7/6rMzX8QseKlX2OYJotuSFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUBlFX%2FbtsOLze6pg7%2F6rMzX8QseKlX2OYJotuSFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1530&quot; height=&quot;1057&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1530&quot; data-origin-height=&quot;1057&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Grafana Ingress 설정에서 애를 먹었지만 잘 적용되었다.&lt;br /&gt;이렇게 해서 한층 더 안전한 NAS 서버 운영을 할 수 있게 되었다.&lt;br /&gt;집에 굴러다니는 라즈베리파이가 있다면 이런 식으로 리버스 프록시 서버로 활용하면 아주 좋을 것으로 예상된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;475&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xmP3m/btsOLyAsquT/62LOfqkil0HRgO4Y7cWKIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xmP3m/btsOLyAsquT/62LOfqkil0HRgO4Y7cWKIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xmP3m/btsOLyAsquT/62LOfqkil0HRgO4Y7cWKIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxmP3m%2FbtsOLyAsquT%2F62LOfqkil0HRgO4Y7cWKIK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;297&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;오늘도 하얗게 조져졌다....&lt;/s&gt;&lt;/p&gt;</description>
      <category>Linux/Raspberry Pi</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/62</guid>
      <comments>https://09labs.tistory.com/62#entry62comment</comments>
      <pubDate>Sat, 21 Jun 2025 01:46:38 +0900</pubDate>
    </item>
    <item>
      <title>[DevOps] 홈서버에 Kubernetes + ArgoCD + Ingress Nginx를 구축해보자</title>
      <link>https://09labs.tistory.com/61</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 DevOps 업무를 진행하다보니 집에서도 연습을 할 필요성을 느껴서 지난번에 구매한 NAS에&lt;br /&gt;Kubernetes를 설치해보기로 했다. Docker를 미리 설치해두었고 Kubernetes를 on-premise 환경에 구축하는 것은&lt;br /&gt;상당히 어렵기 때문에 경량 Kubernetes인 k3d를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 아래 내용을 반영하여 서비스 배포까지 고려하여 환경을 구축했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Ingress Nginx : traefik 대신 Ingress Controller로 사용&lt;br /&gt;- ArgoCD : helm chart로 만든 서비스를 지속적으로 배포하기 위해 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사전에 OMV NAS에 미리 Docker를 설치하고 진행하는 점을 감안해야 한다.&lt;br /&gt;그럼 시-작&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;K3D 설치 후 클러스터 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750084829549&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어를 입력하면 k3d를 자동으로 설치해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1750084979880&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# k9s 설치
$ wget https://github.com/derailed/k9s/releases/latest/download/k9s_linux_amd64.deb &amp;amp;&amp;amp; apt install ./k9s_linux_amd64.deb &amp;amp;&amp;amp; rm k9s_linux_amd64.deb

# kubectl 설치
$ curl -LO &quot;https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl&quot;

# kubectl 실행권한 부여 후 디렉토리 이동
$ chmod +x kubectl
$ sudo mv kubectl /usr/local/bin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 관리의 편의성을 위해 &lt;a href=&quot;https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;kubectl&lt;/a&gt;과 &lt;a href=&quot;https://github.com/derailed/k9s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;k9s&lt;/a&gt;를 설치해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 클러스터 생성은 k3d 명령어를 사용하여 생성했다.&lt;/p&gt;
&lt;pre id=&quot;code_1750085097620&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ k3d cluster create &amp;lt;cluster name&amp;gt; -a &amp;lt;agent number&amp;gt; -s &amp;lt;server number&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 실행하면 워커노드와 컨트롤 플레인 노드의 갯수를 지정하여 생성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의해야할 점은 k3d는 기본적으로 traefik을 ingress controller로 사용한다.&lt;br /&gt;따라서 traefik을 비활성화해야 Ingress Nginx 설치 시 Pending 상태로 고정되는 것을 방지할 수 있다.&lt;br /&gt;마지막으로 k3d Load Balancer의 80, 443 포트를 포트포워딩을 통해 외부로 노출시켜야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;On-premise 환경에 설치할 경우 자동으로 80, 443 포트가 노출되지만 k3d는 Docker Container에 클러스터가&lt;br /&gt;생성되기 때문에 Docker Container중 k3d Load balancer에 포트포워딩 설정을 반영해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만, 80, 443을 직접 노출하면 공격 대상이 되기 쉬우므로 60880, 63443과 같이 포트를 변경해서 노출시켰다.&lt;br /&gt;나는 DDNS를 사용하고 있기 때문에 공유기와 Docker Container의 포트포워딩을 아래와 같이 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 공유기 80 포트 -&amp;gt; NAS 60880 -&amp;gt; Docker 80&lt;br /&gt;- 공유기 443 포트 -&amp;gt; NAS 60443 -&amp;gt; Docker 443&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최종적으로 클러스터 생성 명령어는 아래와 같이 실행하면 된다.&lt;br /&gt;&amp;lt;cluster name&amp;gt; 은 생성하고 싶은 클러스터 이름으로 설정하면 되고 -a, -s의 숫자는 원하는 워커노드, 컨트롤 플레인 노드&lt;br /&gt;숫자만큼 변경해주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;--k3s-args &quot;--disable=traefik@server:*&quot;&lt;/b&gt;&lt;/i&gt;은 traefik을 비활성화하는 옵션이다.&lt;/p&gt;
&lt;pre id=&quot;code_1750085517720&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ k3d cluster create &amp;lt;cluster name&amp;gt; -a 3 -s 1 --k3s-arg &quot;--disable=traefik@server:*&quot; --port 60880:80@loadbalancer --port 60443:443@loadbalancer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;553&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fp48W/btsODJva5Ts/wEHftCyg2HPYXcsQWK0y60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fp48W/btsODJva5Ts/wEHftCyg2HPYXcsQWK0y60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fp48W/btsODJva5Ts/wEHftCyg2HPYXcsQWK0y60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFp48W%2FbtsODJva5Ts%2FwEHftCyg2HPYXcsQWK0y60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1439&quot; height=&quot;553&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;553&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클러스터 생성 완료 후 k9s 명령어를 실행하면 위와 같이 클러스터가 정상적으로 생성된 것을 알 수 있다.&lt;br /&gt;(argocd, ingress-nginx 설치 후에 캡쳐)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Helm 설치하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Helm 공식문서 : &lt;a href=&quot;https://helm.sh/docs/intro/install/#from-apt-debianubuntu&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://helm.sh/docs/intro/install/#from-apt-debianubuntu&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750085845030&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg &amp;gt; /dev/null
$ sudo apt-get install apt-transport-https --yes
$ echo &quot;deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main&quot; | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
$ sudo apt-get update
$ sudo apt-get install helm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Helm Chart로 어플리케이션들을 배포하기 전에 Helm을 설치해줬다.&lt;br /&gt;공식 문서를 참고하면 OS별로 설치 방법이 나와있다. OMV NAS는 Debian 기반이라서 Debian/Ubuntu 섹션을 참고했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Ingress Nginx 설치하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1750085789540&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
$ helm repo update
$ helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. ingress nginx repo 추가&lt;br /&gt;2. helm repo update&lt;br /&gt;3. ingress nginx 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 순서로 진행하면 k3d 클러스터에 ingress-nginx가 설치되고 아래와 같이 Load Balancer로 배포가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1441&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biObZU/btsOCEVZeyi/JdwCczHwcA4W7ixGbBc8A0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biObZU/btsOCEVZeyi/JdwCczHwcA4W7ixGbBc8A0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biObZU/btsOCEVZeyi/JdwCczHwcA4W7ixGbBc8A0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiObZU%2FbtsOCEVZeyi%2FJdwCczHwcA4W7ixGbBc8A0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1441&quot; height=&quot;240&quot; data-origin-width=&quot;1441&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;br /&gt;ArgoCD 설치하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에 가장 많이 삽질을 한 부분이 ArgoCD 설치이다.&lt;br /&gt;기존에는 /etc/hosts에 도메인을 추가하고 공유기 IP 주소로 접근하도록 만들었었는데 공유기 DDNS로 접속하게 하려니&lt;br /&gt;공유기의 도메인이 test.tplink.com과 같이 서브도메인이 이미 설정된 상태로 제공이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직장동료에게 물어보니 Helm Chart에서 ingress 설정에 root path를 별도로 지정하면 도메인의 하위 경로로&lt;br /&gt;접속이 가능하게 배포가 가능하다고 했다.&lt;/p&gt;
&lt;pre id=&quot;code_1750086350070&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ helm repo add argo https://argoproj.github.io/argo-helm
$ helm repo update
$ helm pull argo/argo-cd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 ArgoCD repo추가 후 Helm Chart를 다운로드 했다.&lt;br /&gt;Helm Chart에서 values.yaml에 직접 수정하지 않고 values-override.yaml 파일을 생성해서 필요한 값만 추가했다.&lt;/p&gt;
&lt;div&gt;
&lt;style&gt;body{margin:0;} 
		.hljs{ width: 650px; font-family: &quot;Courier New&quot;, Courier, monospace; margin: 0; /* firefox, download/view-in-new-window */ }
	&lt;/style&gt;
&lt;/div&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;display: block; overflow-x: auto; background: #19171c; color: #8b8792; padding: 0.5em;&quot;&gt;&lt;code&gt;global:
  domain: &quot;test.tplinkrouter.com&quot;

configs:
  params:
    server.insecure: true

server:
  ingress:
    enabled: true
    hostname: &quot;test.tplinkrouter.com&quot;
    ingressClassName: &quot;nginx&quot;
    annotations:
      nginx.ingress.kubernetes.io/backend-protocol: HTTP
  extraArgs:
    - --insecure
    - --rootpath=/argocd&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 설정하면 &lt;b&gt;test.tplinkrouter.com/argocd &lt;/b&gt;와 같은 형태로 서브도메인은 공유기 DDNS에서 제공하는&lt;br /&gt;도메인을 사용하고 하위 경로인 argocd로 접근이 가능하게 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1750087148481&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ helm install argocd . -f ./values-override.yaml --namespace=argocd --create-namespace&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 다운받은 ArgoCD helm chart 디렉토리로 이동해서 values-override.yaml 파일에 위에서 작성한 코드를&lt;br /&gt;붙여넣고 helm install 명령어로 ArgoCD를 설치해주었다.&lt;/p&gt;
&lt;pre id=&quot;code_1750087233801&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath=&quot;{.data.password}&quot; | base64 -d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 완료 후 가장 마지막에 위 명령어를 입력하라고 뜨는데 Admin 계정의 초기 비밀번호이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ID : admin&lt;br /&gt;Password : 위 명령어로 나온 결과를 입력&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;605&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn9iek/btsOBZTu1qX/87d29bk7yOWwTAhJiotbD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn9iek/btsOBZTu1qX/87d29bk7yOWwTAhJiotbD0/img.png&quot; data-alt=&quot;ArgoCD 로그인 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn9iek/btsOBZTu1qX/87d29bk7yOWwTAhJiotbD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn9iek%2FbtsOBZTu1qX%2F87d29bk7yOWwTAhJiotbD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;968&quot; height=&quot;605&quot; data-origin-width=&quot;968&quot; data-origin-height=&quot;605&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ArgoCD 로그인 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;641&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7sIkB/btsODJ9L2hx/VGkbidi1s8ciDHSH9dHDD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7sIkB/btsODJ9L2hx/VGkbidi1s8ciDHSH9dHDD0/img.png&quot; data-alt=&quot;ArgoCD 초기 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7sIkB/btsODJ9L2hx/VGkbidi1s8ciDHSH9dHDD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7sIkB%2FbtsODJ9L2hx%2FVGkbidi1s8ciDHSH9dHDD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1066&quot; height=&quot;641&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;641&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;ArgoCD 초기 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게해서 K3D Cluster 생성, Ingress Nginx 설치, ArgoCD 설치까지 완료했다.&lt;br /&gt;다음 포스팅에서는 ArgoCD에 Application을 생성하고 Repository 연동까지 해볼 예정이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xo1HC/btsOEbLtQ0M/gBChOddfhGKtWZOhimRSCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xo1HC/btsOEbLtQ0M/gBChOddfhGKtWZOhimRSCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xo1HC/btsOEbLtQ0M/gBChOddfhGKtWZOhimRSCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxo1HC%2FbtsOEbLtQ0M%2FgBChOddfhGKtWZOhimRSCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;232&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Linux</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/61</guid>
      <comments>https://09labs.tistory.com/61#entry61comment</comments>
      <pubDate>Tue, 17 Jun 2025 00:25:03 +0900</pubDate>
    </item>
    <item>
      <title>[Bambu Lab] Home Assistant를 Docker Compose에 설치해보자</title>
      <link>https://09labs.tistory.com/59</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;2015년에 처음 3D 프린터를 접하고 거의 4~5 종류의 프린터를 사용해본 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgbO7L/btsOAvruYxf/nzcu2X6kma9FcXmouVDMO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgbO7L/btsOAvruYxf/nzcu2X6kma9FcXmouVDMO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgbO7L/btsOAvruYxf/nzcu2X6kma9FcXmouVDMO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgbO7L%2FbtsOAvruYxf%2Fnzcu2X6kma9FcXmouVDMO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;750&quot; height=&quot;736&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;736&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 구매한 3D 프린터는 Sunhokey Prusa i3 제품이었다.&lt;br /&gt;Original Prusa i3랑은 완전히 연관이 없는 제품이다. 프레임은 전부 아크릴이고 연마봉으로 된 레일, RAPMS 1.4 보드,&lt;br /&gt;아두이노 메가, 2004 LCD 조합으로 된 제품이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모터가 나름 소음이 적은 제품이어서 쓸만했던 것으로 기억한다.&lt;br /&gt;테스트용 필라멘트로 ABS를 출력하다가 수축이 너무 심해서 바로 PLA를 따로 구매했다.&lt;br /&gt;(알리 판매자는 왜 ABS를 보내줬을까....)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자작도 몇번 해보고 마지막으로 Original Prusa i3 MK3를 Prusa Bear로 모딩을 하고 한동안 잘 사용하다가&lt;br /&gt;주변에서 계속 뱀부랩 뱀부랩 하는 이야기를 들었다. 좋아봐야 얼마나 좋겠어...? 싶었는데 다 죽어버린 3D프린터 시장에서&lt;br /&gt;계속 이야기가 들리는게 믿기지가 않았다. 지인이 마침 한 대를 팔아도 된다고 해서 출력 테스트를 보고 바로 구매했다. &lt;br /&gt;600mm/s라는 말도 안되는 속도로 출력이 가능하다고 해서 테스트 해봤는데 이미 기본 출력 속도가 너무 빨라서 충격을 먹었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여튼 Bambu Lab P1S를 사용하다보니 내수용이라 불편한 점이 꽤 많았다.&lt;br /&gt;핸디앱이 지원이 되지 않는다는 점이 가장 컸고 이를 해결하기 위해서 HA (Home Assistant)나 Octoeverywhere 같은&lt;br /&gt;서드파티 앱을 사용한다고 들어서 이 참에 HA를 구성해보기로 했다.&lt;br /&gt;참고로 Octoeverywhere도 인터페이스가 깔끔해서 좋았지만 제어가 안된다는 점이 가장 컸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버 환경 구성&lt;/b&gt;&lt;br /&gt;Intel N100 CPU + 16GB RAM + 512GB NVMe (&lt;a href=&quot;https://09labs.tistory.com/57&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://09labs.tistory.com/57&lt;/a&gt;)&lt;br /&gt;Openmediavault에 Docker engine 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Compose 파일 작성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1749984132272&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;services:
  homeassistant:
    container_name: homeassistant
    image: &quot;ghcr.io/home-assistant/home-assistant:stable&quot;
    volumes:
      - /root/ha/config:/config
      - /etc/localtime:/etc/localtime:ro
      - /run/dbus:/run/dbus:ro
    restart: unless-stopped
    privileged: true
    network_mode: host&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;volumes의 /config 디렉토리를 호스트쪽 /root/ha/config로 변경하였다 (OMV에서 Shared 폴더 사용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HACS (Home Assistant Community Store) 설치&lt;br /&gt;HACS는 컨테이너에 접속해서 직접 설치해줘야 한다. 이 부분은 나중에 compose 파일에 녹여내거나 Dockerfile을 따로 작성하는게 좋을듯 싶다.&lt;/p&gt;
&lt;pre id=&quot;code_1749984378773&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ wget -O - https://get.hacs.xyz | bash -
Connecting to get.hacs.xyz (172.67.68.101:443)
Connecting to raw.githubusercontent.com (185.199.109.133:443)
writing to stdout
-                    100% |***********************************************************|  4990  0:00:00 ETA
written to stdout
INFO: Trying to find the correct directory...
INFO: Found Home Assistant configuration directory at '/config'
INFO: Creating custom_components directory...
INFO: Changing to the custom_components directory...
INFO: Downloading HACS
Connecting to github.com (20.200.245.247:443)
Connecting to github.com (20.200.245.247:443)
Connecting to objects.githubusercontent.com (185.199.110.133:443)
saving to 'hacs.zip'
hacs.zip             100% |***********************************************************| 18.1M  0:00:00 ETA
'hacs.zip' saved
INFO: Creating HACS directory...
INFO: Unpacking HACS...

INFO: Verifying versions
INFO: Current version is 2025.6.1, minimum version is 2024.4.1

INFO: Removing HACS zip file...
INFO: Installation complete.

INFO: Remember to restart Home Assistant before you configure it&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 완료 후 HA를 설정하려면 8123 포트로 접속한다.&lt;br /&gt;compose.yaml에서 network를 host로 해놨기 때문에 Docker engine이 돌아가는 서버의 IP로 접속하면 된다.&lt;br /&gt;설치 완료 후 HACS를 설정하기 위해선 재부팅 1회 필요.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;HACS 및 HA-Bambulab 설치&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1324&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XjS97/btsOCDH767N/UbdMdKMKeweHWarRbMAvj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XjS97/btsOCDH767N/UbdMdKMKeweHWarRbMAvj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XjS97/btsOCDH767N/UbdMdKMKeweHWarRbMAvj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXjS97%2FbtsOCDH767N%2FUbdMdKMKeweHWarRbMAvj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1324&quot; height=&quot;728&quot; data-origin-width=&quot;1324&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HACS 설치 후 재부팅이 완료되면 설정 -&amp;gt; 기기 및 서비스로 들어간다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;783&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cURy9K/btsOAKINpI0/wJyWgBt8kaInukHXiRn36K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cURy9K/btsOAKINpI0/wJyWgBt8kaInukHXiRn36K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cURy9K/btsOAKINpI0/wJyWgBt8kaInukHXiRn36K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcURy9K%2FbtsOAKINpI0%2FwJyWgBt8kaInukHXiRn36K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1165&quot; height=&quot;783&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;783&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8XWUJ/btsOCyzX6Yq/Dld5yUhjE8BjydRFl936I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8XWUJ/btsOCyzX6Yq/Dld5yUhjE8BjydRFl936I1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8XWUJ/btsOCyzX6Yq/Dld5yUhjE8BjydRFl936I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8XWUJ%2FbtsOCyzX6Yq%2FDld5yUhjE8BjydRFl936I1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1158&quot; height=&quot;716&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;716&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우측 하단 통합구성요소 추가하기를 눌러서 HACS를 검색한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4bFw8/btsODi4yVTD/Pe0vkzKv1OYjPkB37vNUQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4bFw8/btsODi4yVTD/Pe0vkzKv1OYjPkB37vNUQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4bFw8/btsODi4yVTD/Pe0vkzKv1OYjPkB37vNUQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4bFw8%2FbtsODi4yVTD%2FPe0vkzKv1OYjPkB37vNUQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1119&quot; height=&quot;720&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HA-Bambulab &lt;a href=&quot;https://docs.page/greghesp/ha-bambulab/installation&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;공식 문서&lt;/a&gt;에서 Automatic Install에 존재하는 &lt;i&gt;&lt;b&gt;Open HACS REPOSITORY ON MY&lt;/b&gt;&lt;/i&gt;를 누르면 HACS를 통해 자동으로 BambuLab 컴포넌트를 추가할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Bambu Lab 프린터 연동&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bambu Lab 프린터는 내수 / 글로벌 버전으로 나뉜다. 내수 버전은 중국 내수용으로 Bambu Handy 어플이 지원이 안된다.&lt;br /&gt;즉, 지금과 같이 Home Assistant나 Octoeverywhere과 같은 서드파티로 연결해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 순서&lt;br /&gt;- Bambu Lab 컴포넌트 설치&lt;br /&gt;- 설정 - 기기 및 서비스 - 통합구성요소 추가 - Bambu Lab 컴포넌트 추가&lt;br /&gt;- 프린터 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1469&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRKlVV/btsOBgmO9Wb/KJQOt3aBy2atsyN6km87vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRKlVV/btsOBgmO9Wb/KJQOt3aBy2atsyN6km87vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRKlVV/btsOBgmO9Wb/KJQOt3aBy2atsyN6km87vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRKlVV%2FbtsOBgmO9Wb%2FKJQOt3aBy2atsyN6km87vk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1469&quot; height=&quot;896&quot; data-origin-width=&quot;1469&quot; data-origin-height=&quot;896&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 &amp;gt; 우측 하단 통합구성요소 추가하기 &amp;gt; Bambu Lab 검색 후 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kMcqM/btsOBXUBbrv/gmtyYwkKkhdSJcKQo8BPLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kMcqM/btsOBXUBbrv/gmtyYwkKkhdSJcKQo8BPLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kMcqM/btsOBXUBbrv/gmtyYwkKkhdSJcKQo8BPLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkMcqM%2FbtsOBXUBbrv%2FgmtyYwkKkhdSJcKQo8BPLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1467&quot; height=&quot;788&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bambu Lab 프린터의 버전에 따라 아래와 같이 설정한다.&lt;br /&gt;- 글로벌 : 뱀부랩 클라우드&lt;br /&gt;- 내수용 : 랜모드&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;980&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wJtj8/btsOBfuZMlj/DaLHvNNrft0ONBzGgul9rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wJtj8/btsOBfuZMlj/DaLHvNNrft0ONBzGgul9rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wJtj8/btsOBfuZMlj/DaLHvNNrft0ONBzGgul9rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwJtj8%2FbtsOBfuZMlj%2FDaLHvNNrft0ONBzGgul9rK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1467&quot; height=&quot;980&quot; data-origin-width=&quot;1467&quot; data-origin-height=&quot;980&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 프린터의 IP주소, 시리얼번호, Access Code를 입력하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내수용 프린터에서 위 정보들을 찾기 어렵다면 아래 내용과 링크를 참고한다.&lt;br /&gt;Access Code : &lt;a href=&quot;https://wiki.bambulab.com/en/knowledge-sharing/enable-lan-mode#p1pp1s-series-printers&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wiki.bambulab.com/en/knowledge-sharing/enable-lan-mode#p1pp1s-series-printers&lt;/a&gt;&lt;br /&gt;Serial 번호 : &lt;a href=&quot;https://wiki.bambulab.com/en/general/find-sn#p1-series&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://wiki.bambulab.com/en/general/find-sn#p1-series&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;중국 내수용 프린터는 꼭! LAN Only Mode를 활성화 해야 서드파티 앱에 연결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;Access Code 위치&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;369&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yUc7V/btsOBBdvW4d/aS74XYe8CZG0fqFNrE8f8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yUc7V/btsOBBdvW4d/aS74XYe8CZG0fqFNrE8f8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yUc7V/btsOBBdvW4d/aS74XYe8CZG0fqFNrE8f8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyUc7V%2FbtsOBBdvW4d%2FaS74XYe8CZG0fqFNrE8f8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;955&quot; height=&quot;369&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nIPXK/btsOA14Hy2u/QTZuDriaXIqGCDMjEdFODK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nIPXK/btsOA14Hy2u/QTZuDriaXIqGCDMjEdFODK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nIPXK/btsOA14Hy2u/QTZuDriaXIqGCDMjEdFODK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnIPXK%2FbtsOA14Hy2u%2FQTZuDriaXIqGCDMjEdFODK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;889&quot; height=&quot;344&quot; data-origin-width=&quot;889&quot; data-origin-height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌측 세 번째 메뉴 &amp;gt; WLAN 에서 IP와 Access Code를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;Serial 번호 위치&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNrtmN/btsODpihl15/wZZquLtKb0JR47DIbFYkUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNrtmN/btsODpihl15/wZZquLtKb0JR47DIbFYkUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNrtmN/btsODpihl15/wZZquLtKb0JR47DIbFYkUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNrtmN%2FbtsODpihl15%2FwZZquLtKb0JR47DIbFYkUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1825&quot; height=&quot;684&quot; data-origin-width=&quot;1825&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌측 세 번째 메뉴 &amp;gt; Device &amp;gt; Printer 에서 확인할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Home Assistant 첫 화면&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;1127&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciZQYJ/btsODmeQ3TJ/s29afkEDe6zu3gXf8PyEZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciZQYJ/btsODmeQ3TJ/s29afkEDe6zu3gXf8PyEZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciZQYJ/btsODmeQ3TJ/s29afkEDe6zu3gXf8PyEZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciZQYJ%2FbtsODmeQ3TJ%2Fs29afkEDe6zu3gXf8PyEZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1372&quot; height=&quot;1127&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;1127&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flow rate Calibration 중이라서 위와 같이 출력중인 스트리밍 카메라 화면과 출력물 섬네일이 표시되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 위 과정까지 마무리하고 대시보드 꾸미는 것은 차츰 진행해야겠다. 찾아보니 lovelace 플러그인을 활용하고&lt;br /&gt;대시보드를 꾸미기 위해서는 YAML을 수정해서 구성하는 것으로 예상된다.&lt;/p&gt;</description>
      <category>3D 프린터</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/59</guid>
      <comments>https://09labs.tistory.com/59#entry59comment</comments>
      <pubDate>Sun, 15 Jun 2025 22:59:20 +0900</pubDate>
    </item>
    <item>
      <title>[Electron] 1. Hello World 띄워보기</title>
      <link>https://09labs.tistory.com/58</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 09LABS 입니다.&lt;br /&gt;요즘 프로그래밍을 하면서 Frontend + Backend Application을 만들어보고 싶다는 생각에&lt;br /&gt;새 프로젝트를 시작하면서 Electron에 대해 접하게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqOHco/btsMU9IgHn8/wukXphRHsIRKdWhzu8QhQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqOHco/btsMU9IgHn8/wukXphRHsIRKdWhzu8QhQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqOHco/btsMU9IgHn8/wukXphRHsIRKdWhzu8QhQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqOHco%2FbtsMU9IgHn8%2FwukXphRHsIRKdWhzu8QhQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;200&quot; height=&quot;200&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;동료의 얘기로는 Electron이 가장 많이 사용되는 프레임워크라고 했고 Javascript 이기 때문에 C, C++로 개발을 했었던 제가 처음 접하기에 큰 어려움이 없을 것이라고 했습니다.&lt;br /&gt;Electron은 JavaScript와 HTML, CSS를 사용하여 Desktop Application을 만들 수 있는 Framework 입니다.&lt;br /&gt;Windows, MacOS, Linux 모두 사용할 수 있는 크로스 플랫폼이기 때문에 OS를 가리지 않는다는 장점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 언어를 시작하더라도 Hello World를 띄우는 것이 가장 처음 할 일이겠죠?&lt;br /&gt;&lt;a href=&quot;https://www.electronjs.org/docs/latest/tutorial/quick-start&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Electron 공식 홈페이지&lt;/a&gt; 글을 보고 시작 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;a href=&quot;https://nodejs.org/ko/download/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Node.js&lt;/a&gt;가 설치되어 있어야 합니다. 설치되어있지 않다면 설치를 먼저 하고 오시기 바랍니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Package Initialize&lt;/h4&gt;
&lt;pre id=&quot;code_1742744880663&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm init&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적당히 아무 폴더나 생성한 뒤 위 명령어를 입력합니다. &lt;br /&gt;윈도우에서는 PowerShell을 실행한 뒤 npm.cmd init을 입력해주면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742745063366&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm.cmd init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install &amp;lt;pkg&amp;gt;` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (bambuelectron)
version: (1.0.0)
description:
entry point: (index.js) main.js
test command:
git repository:
keywords:
author:
license: (ISC)

About to write to C:\Users\Documents\testapplication\package.json:     

{
  &quot;name&quot;: &quot;testapplication&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;main&quot;: &quot;main.js&quot;,
  &quot;scripts&quot;: {
  },
  &quot;author&quot;: &quot;&quot;,
  &quot;license&quot;: &quot;ISC&quot;,
  &quot;description&quot;: &quot;&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;entry point만 main.js로 바꿔주고 엔터를 입력해서 넘어가면 위와 같이 package.json 파일을 생성해 줍니다.&lt;br /&gt;그 다음 아래 명령어를 입력해서 Electron Dependency를 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742745148723&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i --save-dev eletron&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 완료하셨다면 start 스크립트를 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742745207422&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;bambuelectron&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;main&quot;: &quot;main.js&quot;,
  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;amp;&amp;amp; exit 1&quot;,
    &quot;start&quot;: &quot;electron .&quot;
  },
  &quot;author&quot;: &quot;&quot;,
  &quot;license&quot;: &quot;ISC&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;devDependencies&quot;: {
    &quot;electron&quot;: &quot;^35.0.3&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 화면을 만들어줄 차례입니다. 폴더에 index.html 파일을 생성해서 아래 내용을 입력해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742745319862&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --&amp;gt;
    &amp;lt;meta http-equiv=&quot;Content-Security-Policy&quot; content=&quot;default-src 'self'; script-src 'self'&quot;&amp;gt;
    &amp;lt;title&amp;gt;Hello World!&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;
    We are using Node.js &amp;lt;span id=&quot;node-version&quot;&amp;gt;&amp;lt;/span&amp;gt;,
    Chromium &amp;lt;span id=&quot;chrome-version&quot;&amp;gt;&amp;lt;/span&amp;gt;,
    and Electron &amp;lt;span id=&quot;electron-version&quot;&amp;gt;&amp;lt;/span&amp;gt;.
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 HTML로 작성한 웹 페이지를 Application 창에 띄울 차례입니다.&lt;br /&gt;main.js 파일을 만들고 아래와 같이 입력합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742745476428&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { app, BrowserWindow } = require('electron');
const path = require('path');
 
const createWindow = () =&amp;gt; {
    const win = new BrowserWindow({
        width: 640,
        height: 480,
        webPreferences: { preload: path.join(__dirname, 'preload.js') }
    });
 
    win.loadFile('index.html');
};
 
app.whenReady().then(() =&amp;gt; {
    createWindow();
 
    app.on('activate', () =&amp;gt; {
        if (BrowserWindow.getAllWindows().length === 0) createWindow();
    });
});
 
app.on('window-all-closed', () =&amp;gt; {
    if (process.platform !== 'darwin') app.quit();
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Hello World를 띄우는 것이기 때문에 자세한 설명은 생략하겠습니다.&lt;br /&gt;간단히 요약하면 윈도우의 생명 주기, 어떤 화면을 띄울 것인지, 창 크기는 어떻게 되는지 정의가 되어있습니다.&lt;br /&gt;마지막으로 preload.js 파일을 생성해서 아래 내용을 입력해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742745588461&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;window.addEventListener('DOMContentLoaded', () =&amp;gt; {
    const replaceText = (selector, text) =&amp;gt; {
        const element = document.getElementById(selector)
        if (element) element.innerText = text
    }
 
    for (const type of ['chrome', 'node', 'electron']) {
        replaceText(`${type}-version`, process.versions[type]);
    }
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;preload.js는 Electron과 종속성에 대한 내용을 웹 페이지에 띄우기 위한 내용이 정의되어 있습니다.&lt;br /&gt;작성이 완료되었다면 아래와 같이 명령어를 입력합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1742745742061&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ npm start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;473&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4VaEH/btsMVbsxPw9/A45iUMHh3BTBuO8mVPUuHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4VaEH/btsMVbsxPw9/A45iUMHh3BTBuO8mVPUuHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4VaEH/btsMVbsxPw9/A45iUMHh3BTBuO8mVPUuHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4VaEH%2FbtsMVbsxPw9%2FA45iUMHh3BTBuO8mVPUuHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;626&quot; height=&quot;473&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;473&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;창에 HTML로 작성된 웹 페이지가 실행된 것을 알 수 있습니다.&lt;br /&gt;의도한대로 Cromium, Node.js, Eletron 버전이 표시됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 첫 Electron Application을 만들어 봤습니다.&lt;br /&gt;다음장에서는 UI를 꾸미고 Electron으로 앱을 실행하는 방법에 대해 알아보겠습니다.&lt;/p&gt;</description>
      <category>코딩하자</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/58</guid>
      <comments>https://09labs.tistory.com/58#entry58comment</comments>
      <pubDate>Mon, 24 Mar 2025 01:16:30 +0900</pubDate>
    </item>
    <item>
      <title>[소소한 지름] AOOSTAR WTR PRO NAS - Intel N100</title>
      <link>https://09labs.tistory.com/57</link>
      <description>
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;br /&gt;09LABS 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작년 8월에 마지막 글을 올리고 긴 시간이 흘렀습니다.&lt;br /&gt;그동안 많은 일이 있었습니다. 정들었던 쏘카를 떠나 새 직장에 적응하고 해외 출장도 여러번&lt;br /&gt;다녀오느라 많이 바빴습니다. 이제야 조금 쉴 틈이 생겨서 다시 블로그를 해볼까 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 자작 NAS를 구입하여 리뷰를 올립니다.&lt;br /&gt;전에 라이젠 3600으로 자작 NAS를 만들다가 TDP가 너무 높아 상시로 구동하기엔 다소 무리가 있어보여&lt;br /&gt;NAS를 알아보다가 구매하게 되었습니다.&lt;br /&gt;&lt;br /&gt;AOOSTAR WTR PRO라는 제품이고 Intel N100 프로세서가 탑재되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnJ18F/btsLWxkftel/Y2d1Wt7MOaauzOKWpXZoL1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnJ18F/btsLWxkftel/Y2d1Wt7MOaauzOKWpXZoL1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnJ18F/btsLWxkftel/Y2d1Wt7MOaauzOKWpXZoL1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnJ18F%2FbtsLWxkftel%2FY2d1Wt7MOaauzOKWpXZoL1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;박스는 배송중 모서리만 살짝 찌그러져서 왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_01.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uebNQ/btsLVLiX983/YaOLqvdmSiHMN2H75E6kWk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uebNQ/btsLVLiX983/YaOLqvdmSiHMN2H75E6kWk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uebNQ/btsLVLiX983/YaOLqvdmSiHMN2H75E6kWk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuebNQ%2FbtsLVLiX983%2FYaOLqvdmSiHMN2H75E6kWk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_01.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_03.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uvvSO/btsLWRpddvA/Cjz6djHwDPnhLkdqWLtFK0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uvvSO/btsLWRpddvA/Cjz6djHwDPnhLkdqWLtFK0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uvvSO/btsLWRpddvA/Cjz6djHwDPnhLkdqWLtFK0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuvvSO%2FbtsLWRpddvA%2FCjz6djHwDPnhLkdqWLtFK0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_03.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전면에는 제품 사진과 로고가 찍혀있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_05.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nFd4J/btsLXPYwdRR/XKMbTY26QAuos43EWDBuRK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nFd4J/btsLXPYwdRR/XKMbTY26QAuos43EWDBuRK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nFd4J/btsLXPYwdRR/XKMbTY26QAuos43EWDBuRK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnFd4J%2FbtsLXPYwdRR%2FXKMbTY26QAuos43EWDBuRK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_05.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;박스를 꺼내보면 완충재와 함께 충전기, 메뉴얼이 들어있습니다.&lt;br /&gt;완충재가 튼튼해서 박스 모서리가 찌그러져도 큰 걱정이 없어보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_06.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvOw0O/btsLXutwMOu/YJIaQkn7lu96sAvdGvdk21/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvOw0O/btsLXutwMOu/YJIaQkn7lu96sAvdGvdk21/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvOw0O/btsLXutwMOu/YJIaQkn7lu96sAvdGvdk21/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvOw0O%2FbtsLXutwMOu%2FYJIaQkn7lu96sAvdGvdk21%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_06.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제품 좌측면에는 RJ45 2개, DP 1개, HDMI 1개, USB 4개, C타입 1개, 전원, 이어폰 잭이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_07.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEDKLg/btsLYbfXggF/XIYhHznbHKlEKFXJEVNLcK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEDKLg/btsLYbfXggF/XIYhHznbHKlEKFXJEVNLcK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEDKLg/btsLYbfXggF/XIYhHznbHKlEKFXJEVNLcK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEDKLg%2FbtsLYbfXggF%2FXIYhHznbHKlEKFXJEVNLcK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_07.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전면에는 플라스틱으로 만든 하드 베이 커버가 덮여있습니다.&lt;br /&gt;개인적으로 커버도 알미늄으로 만들었으면 하네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_08.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/diaXFo/btsLX8XR3PC/b0KkXbP7Cm4rAcih4KQW5K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/diaXFo/btsLX8XR3PC/b0KkXbP7Cm4rAcih4KQW5K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/diaXFo/btsLX8XR3PC/b0KkXbP7Cm4rAcih4KQW5K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdiaXFo%2FbtsLX8XR3PC%2Fb0KkXbP7Cm4rAcih4KQW5K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_08.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우측 하단 로고를 슬라이딩하면 전원버튼이 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_10.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7Eh77/btsLXUyJWgg/LgomfcqBeHqhXjqYjzLpzK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7Eh77/btsLXUyJWgg/LgomfcqBeHqhXjqYjzLpzK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7Eh77/btsLXUyJWgg/LgomfcqBeHqhXjqYjzLpzK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7Eh77%2FbtsLXUyJWgg%2FLgomfcqBeHqhXjqYjzLpzK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_10.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드 베이 커버를 벗기면 수평으로 장착된 하드베이 4개를 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_11.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bG0K07/btsLXQC7F77/FOcltyaQsJ7fScMKsxnU2k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bG0K07/btsLXQC7F77/FOcltyaQsJ7fScMKsxnU2k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bG0K07/btsLXQC7F77/FOcltyaQsJ7fScMKsxnU2k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG0K07%2FbtsLXQC7F77%2FFOcltyaQsJ7fScMKsxnU2k%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_11.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20250123_004450672_12.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0eTDc/btsLXqq68Yf/plQNRTbjL2ma2OJU8NQoRk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0eTDc/btsLXqq68Yf/plQNRTbjL2ma2OJU8NQoRk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0eTDc/btsLXqq68Yf/plQNRTbjL2ma2OJU8NQoRk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0eTDc%2FbtsLXqq68Yf%2FplQNRTbjL2ma2OJU8NQoRk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;KakaoTalk_20250123_004450672_12.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하단에는 M.2 SATA 2개와 메모리를 꽂을 수 있는 공간이 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_20250123_004450672_13.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IbiVJ/btsLVEjR605/Qf1NpKSVn5rFbnR8mpV0pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IbiVJ/btsLVEjR605/Qf1NpKSVn5rFbnR8mpV0pK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IbiVJ/btsLVEjR605/Qf1NpKSVn5rFbnR8mpV0pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIbiVJ%2FbtsLVEjR605%2FQf1NpKSVn5rFbnR8mpV0pK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1440&quot; height=&quot;1080&quot; data-filename=&quot;edited_KakaoTalk_20250123_004450672_13.jpg&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 2280 SSD 500GB와 메모리 16 GB를 꽂아주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 제품은 Intel N100과 AMD R7-5825U 두 가지 버전으로 출시하는데 가격은 11만원 정도 차이가 납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Intel N100 : 269,000원&lt;br /&gt;AMD R7-5825U : 379,400원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고사양으로 돌리는 작업을 하거나 사무용으로 쓰지 않고 NAS와 Kubernetes, GitLab, ArgoCD, 게임서버 용도로&lt;br /&gt;사용할 목적으로 구매했습니다.&lt;br /&gt;OS는 OMV를 설치했고 금방 마무리 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기에는 기본 팬이 시끄럽다는 이야기가 있는데 굳이 바꿀 필요는 없어보이고&lt;br /&gt;추후에 HDD를 구매해서 RAID 구성 후 NAS와 Object Storage를 함께 사용해볼까 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자작 NAS를 고려하시는 분들께는 아주 좋은 구성이라고 생각됩니다.&lt;br /&gt;메인보드, CPU, 메모리, 케이스, 파워 등을 구입하다보면 어느새 30만원은 훌쩍 넘겨버리더군요.&lt;br /&gt;269,000원에 완제품을 구매할 수 있는 점은 매우 큰 메리트라고 생각됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;총평&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점&lt;br /&gt;- 저렴한 가격, CPU 사양에 따른 옵션 선택 가능&lt;br /&gt;- 완제품이기 때문에 OS만 설치해서 즉시 사용 가능&lt;br /&gt;- N100이어도 롤을 돌릴 수 있다고 함. 성능이 전혀 나쁘지 않음&lt;br /&gt;- TDP가 6W이기 때문에 매우 저전력으로 작동&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;br /&gt;- 2베이 제품의 메인보드를 재활용한 설계로 인해 측면에 포트가 위치함&lt;br /&gt;- HDD 홀더가 약간 부실해보임&lt;br /&gt;- N100은 메모리가 싱글채널이라 1개만 꽂을 수 있음. (최대 32GB) AMD R7-5825U는 2개 장착 가능&lt;br /&gt;- AS의 부재(?)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;결론 : 잘샀다&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>일상/지름</category>
      <category>aoostar</category>
      <category>intel n100</category>
      <category>N100</category>
      <category>NAS</category>
      <category>wtr pro</category>
      <category>나스</category>
      <category>자작나스</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/57</guid>
      <comments>https://09labs.tistory.com/57#entry57comment</comments>
      <pubDate>Thu, 23 Jan 2025 01:09:54 +0900</pubDate>
    </item>
    <item>
      <title>[Active Pedal] 1. Simucube Active Pedal DIY - 분석</title>
      <link>https://09labs.tistory.com/56</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 09LABS 입니다.&lt;br /&gt;오랜만에 DIY 글로 찾아왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 레이싱 시뮬레이터에 푹 빠져서 주변 장비들을 만들고 있습니다.&lt;br /&gt;현재까지 완료한 프로젝트는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 페달 접이식 Direct Drive Base 거치대&lt;br /&gt;2. DIY 2UN 모션 시뮬레이터&lt;br /&gt;3. 윈드 제너레이터&lt;br /&gt;4. 5인치 DDU&lt;br /&gt;5. 페달 진동모터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진행중인 프로젝트는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Porsche 911 GT3 Steering Button Box&lt;br /&gt;2. Froce Feedback Active Pedal&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 Simucube 사의 Active Pedal에 대해 간략히 알아보고 DIY Active Pedal 프로젝트를 소개할까 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RPGyK/btsIZWBmCQO/2bASwikVJMcbqYVVfq8T41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RPGyK/btsIZWBmCQO/2bASwikVJMcbqYVVfq8T41/img.png&quot; data-alt=&quot;&amp;amp;lt;1. Simucube Active Pedal&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RPGyK/btsIZWBmCQO/2bASwikVJMcbqYVVfq8T41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRPGyK%2FbtsIZWBmCQO%2F2bASwikVJMcbqYVVfq8T41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;720&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;1. Simucube Active Pedal&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진은 Simucube 사의 Active Pedal입니다.&lt;br /&gt;개당 가격이 거의 300만원에 육박하는 매우 고가 장비입니다.&lt;br /&gt;심레이싱에서는 크게 네 가지 페달로 나뉩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Active Pedal&lt;br /&gt;2. Load Cell Pedal&lt;br /&gt;3. Hall effect Pedal&lt;br /&gt;4. Hydualic(유압) Pedal&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 차량은 유압 페달을 사용한다고 보시면 되겠습니다.&lt;br /&gt;다만 Gas Pedal은 차량에 따라 전자식, 기계식 와이어링으로 나뉘기도 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFg4b1/btsI0UoXUkr/mYHpe3ERLvbdRX3zl4yXmk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFg4b1/btsI0UoXUkr/mYHpe3ERLvbdRX3zl4yXmk/img.jpg&quot; data-alt=&quot;&amp;amp;lt;2. 자동차 페달&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFg4b1/btsI0UoXUkr/mYHpe3ERLvbdRX3zl4yXmk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFg4b1%2FbtsI0UoXUkr%2FmYHpe3ERLvbdRX3zl4yXmk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;318&quot; height=&quot;159&quot; data-origin-width=&quot;318&quot; data-origin-height=&quot;159&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;2. 자동차 페달&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 페달은 모두 장단점이 있습니다.&lt;br /&gt;Hall effect 페달은 저렴하지만 답력 조절이 어렵고 조잡한 느낌이 많이 듭니다.&lt;br /&gt;Load Cell 페달은 제조사에 따라 가격대 범위가 매우 넓고 답력 조절이 가능합니다.&lt;br /&gt;유압 페달은 답력 조절이 쉽지만 가격이 비싸고 관리가 용이하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지 방식 모두 베이퍼록, 페이드 현상, 실제 차량의 느낌을 주기는 어렵습니다.&lt;br /&gt;실제 차량에서는 브레이크를 밟을 때 캘리퍼에서 디스크와 마찰이 일어나는 느낌을 받을 수 있지만&lt;br /&gt;심레이싱에서는 대부분의 페달이 물리적으로 피드백을 주지 않기 때문입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HAToS/btsI0dCQaE4/jd8BD2pJrsy1V8DtlBIFCk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HAToS/btsI0dCQaE4/jd8BD2pJrsy1V8DtlBIFCk/img.jpg&quot; data-alt=&quot;&amp;amp;lt;3. Simagic Rumble motor&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HAToS/btsI0dCQaE4/jd8BD2pJrsy1V8DtlBIFCk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHAToS%2FbtsI0dCQaE4%2Fjd8BD2pJrsy1V8DtlBIFCk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;452&quot; height=&quot;452&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;3. Simagic Rumble motor&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해소하기 위하여 페달에 진동모터를 달기도 하지만 페달을 밟는 느낌에 대해&lt;br /&gt;피드백을 주기는 어렵습니다. 대부분 진동모터는 ABS 피드백을 주기 위해 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Simucube사에서는 피드백을 줄 수 있는 Active Pedal을 출시하여 판매중입니다.&lt;br /&gt;다만 가격대가 매우 높기 때문에 쉽게 접하기 어렵습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;655&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJYj23/btsI1W0sX2n/q02nhLFVoTHUIhUjgY4uF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJYj23/btsI1W0sX2n/q02nhLFVoTHUIhUjgY4uF1/img.png&quot; data-alt=&quot;&amp;amp;lt;4. Simucube 페달 배선도&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJYj23/btsI1W0sX2n/q02nhLFVoTHUIhUjgY4uF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJYj23%2FbtsI1W0sX2n%2Fq02nhLFVoTHUIhUjgY4uF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;655&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;655&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;4. Simucube 페달 배선도&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Simucube사의 페달은 아래와 같이 연결됩니다.&lt;br /&gt;단일 페달 사용 시 : 페달 - Simucube Link Hub - PC&lt;br /&gt;2개 이상 사용 시 : 페달 - 이더넷 스위치 - Simucube Link Hub - PC&lt;br /&gt;Passive 페달 혼합 사용 시 : Passive 페달 + Active 페달 - Simucube Link Hub - PC&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;547&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eMtoGz/btsI0vQOVxJ/KQqLhSKKuyHFP427a9eRh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eMtoGz/btsI0vQOVxJ/KQqLhSKKuyHFP427a9eRh0/img.png&quot; data-alt=&quot;&amp;amp;lt;5. Simucube Passive Pedal wiring&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eMtoGz/btsI0vQOVxJ/KQqLhSKKuyHFP427a9eRh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeMtoGz%2FbtsI0vQOVxJ%2FKQqLhSKKuyHFP427a9eRh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;547&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;547&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;5. Simucube Passive Pedal wiring&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Simucube사의 Passive Pedal은 로드셀을 사용하고 6P4C 커넥터를 사용하여 연결됩니다.&lt;br /&gt;타사의 페달을 연결하려면 배선도를 먼저 확인해야하고 호환되지 않을 경우 변환 케이블을 사용해야 합니다.&lt;br /&gt;참고로 Sim Ruito 페달은 4P4C 커넥터를 사용하기 때문에 호환되지 않는 점을 확인하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;914&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/486Fe/btsI0T4IKDy/i62tHk6auwJQqMUkvH262K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/486Fe/btsI0T4IKDy/i62tHk6auwJQqMUkvH262K/img.jpg&quot; data-alt=&quot;&amp;amp;lt;6. Simucube Active Pedal PCB&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/486Fe/btsI0T4IKDy/i62tHk6auwJQqMUkvH262K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F486Fe%2FbtsI0T4IKDy%2Fi62tHk6auwJQqMUkvH262K%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1200&quot; height=&quot;914&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;914&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;6. Simucube Active Pedal PCB&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Simucube사의 페달은 바닥에 PCB가 매립되어 있으며 배선도로 보아 BLDC 모터를 사용하는 것 같습니다.&lt;br /&gt;또한 MCU는 Atmel 칩을 사용하고 있는데 구체적인 모델명은 확인이 어려웠고 ARM 코어를 사용하는 것 같습니다.&lt;br /&gt;이더넷 포트가 있는 것으로 보아 Simucube Link Hub와 통신하기 위한 목적으로 사용하는 것으로 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 저는 재밌는 프로젝트를 하나 발견했습니다.&lt;br /&gt;&lt;a href=&quot;https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723403826628&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&quot; data-og-description=&quot;Contribute to ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&quot; data-og-url=&quot;https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BVXQ4/hyWKJ2dJGU/NrkXmkA0mIkdn6b6WywcnK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BVXQ4/hyWKJ2dJGU/NrkXmkA0mIkdn6b6WywcnK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to ChrGri/DIY-Sim-Racing-FFB-Pedal-Mechanical-Design development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 DIY Active Pedal 프로젝트인데요, 제작비가 대략 40만원 정도 들어간다는 것을 봤고&lt;br /&gt;저도 제작에 들어갔습니다. 물론 Simagic이나 이태리 웨이브, 휴싱벨드 등 훌륭한 제품이 있지만&lt;br /&gt;모두 피드백을 주지 못하는 페달이기 때문에 현재까지는 Sim Ruito 제품을 사용하고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 40만원도 저렴한 가격은 아닙니다만 Simucube사의 제품에 비하면 매우 저렴한 편에 속합니다.&lt;br /&gt;기존 프로젝트와 디스코드 서버에서 공유되고 있는 완성작을 보면 모터의 역전압으로 인하여&lt;br /&gt;파워 서플라이가 손상되는 것을 방지하기 위해 Power Capacitor를 외장형 또는 매립형으로 사용하는데&lt;br /&gt;크기가 커서 모델링에 다소 고민이 많았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 Power PCB를 외장형으로 만들고 ESP32 보드와 ADC 컨버터를 합쳐서 사용하기 위해&lt;br /&gt;별도의 PCB를 설계하여 사용하기로 마음먹었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;810&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bo3us/btsI0MkfJ2W/5knYfYKvV1qdtuTRWmn761/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bo3us/btsI0MkfJ2W/5knYfYKvV1qdtuTRWmn761/img.png&quot; data-alt=&quot;&amp;amp;lt;7. DIY Active Pedal Modeling&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bo3us/btsI0MkfJ2W/5knYfYKvV1qdtuTRWmn761/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBo3us%2FbtsI0MkfJ2W%2F5knYfYKvV1qdtuTRWmn761%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1061&quot; height=&quot;810&quot; data-origin-width=&quot;1061&quot; data-origin-height=&quot;810&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;7. DIY Active Pedal Modeling&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;661&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVjiq7/btsI1paXjmN/0zKI94X6HmxOKfMQw0RUy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVjiq7/btsI1paXjmN/0zKI94X6HmxOKfMQw0RUy0/img.png&quot; data-alt=&quot;&amp;amp;lt;8. DIY Active Pedal PCB&amp;amp;gt;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVjiq7/btsI1paXjmN/0zKI94X6HmxOKfMQw0RUy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVjiq7%2FbtsI1paXjmN%2F0zKI94X6HmxOKfMQw0RUy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;945&quot; height=&quot;661&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;661&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;8. DIY Active Pedal PCB&amp;gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재까지 모델링은 여기까지 진행되었고 부품은 3D 프린터로 제작중입니다.&lt;br /&gt;판매를 목적으로 하지 않기 때문에 모델링은 전반적으로 Simucube 제품을 참고하였습니다.&lt;/p&gt;</description>
      <category>Dev.OWNN/Active Pedal</category>
      <category>3d프린터</category>
      <category>active pedal</category>
      <category>DIY</category>
      <category>심레이싱</category>
      <category>액티브페달</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/56</guid>
      <comments>https://09labs.tistory.com/56#entry56comment</comments>
      <pubDate>Mon, 12 Aug 2024 04:42:50 +0900</pubDate>
    </item>
    <item>
      <title>[ESP-IDF] 3. Task API (feat. 멀티태스킹)</title>
      <link>https://09labs.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 09LABS 입니다.&lt;br /&gt;지난 강의에서는 ESP-IDF 빌드 시스템 구축 후 기본 코드를 작성하는 방법에 대해 알아봤습니다.&lt;br /&gt;이번 강의에서는 멀티태스킹과 유사한 Task API에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티태스킹은 동시에 여러 작업을 수행하는 것을 의미하는데요, 싱글코어 MCU에서는 한 번에 하나의 Task를 실행할 수 있습니다.&lt;br /&gt;따라서 싱글코어 MCU의 경우 Task를 여러개 생성하면 동시에 처리되는 것 처럼 보이지만 스케쥴러에 의해 순차적으로 처리됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;266&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/CPU_%ED%83%80%EC%9E%84&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJFAck/btsEZb8SOGg/NrFP7QAKVtojZDtYGEycd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJFAck%2FbtsEZb8SOGg%2FNrFP7QAKVtojZDtYGEycd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;266&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;266&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;그림1. 싱글코어 멀티태스킹 (위키백과)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림과 같이 프로그램을 3개 실행한다고 했을 때 우선순위가 높은 순서에 따라 프로그램이 실행되는 순서가 결정됩니다.&lt;br /&gt;만약 듀얼코어 MCU를 사용한다면 멀티태스킹이 어떻게 실행될까요?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2024-02-17 오전 1.54.40.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;717&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M4UFF/btsEZahNvWx/za5BY731OYjNiK9bExovBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M4UFF/btsEZahNvWx/za5BY731OYjNiK9bExovBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M4UFF/btsEZahNvWx/za5BY731OYjNiK9bExovBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM4UFF%2FbtsEZahNvWx%2Fza5BY731OYjNiK9bExovBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;510&quot; data-filename=&quot;스크린샷 2024-02-17 오전 1.54.40.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;717&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 사용하는 ESP32-S3 MCU는 듀얼코어 CPU로 구성되어있습니다.&lt;br /&gt;총 2개의 Task를 생성한다고 하면 코어 하나에 하나의 Task를 할당시켜 동시에 두 개의 Task를 실행시킬 수 있습니다.&lt;br /&gt;&lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32/api-reference/system/freertos.html#task-api&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ESP-IDF Task API&lt;/a&gt; 문서를 보면&amp;nbsp;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;xTaskCreatePinnedToCore&lt;/span&gt;&lt;/b&gt; 라는 함수를 사용하여 Task를 실행시킬 Core를 지정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 동시에 실행되어서 실시간으로 데이터를 처리하는 Task와 데이터를 수신하는 Task 두 개를 생성한다고 하면 Core를 나눠서 실행시키면 가장 효과적인 성능을 보여줄 것입니다.&lt;br /&gt;이번 강의에서는 멀티태스킹을 구성하는 방법에 대해 알아보고 0부터 10까지 숫자를 세는 Task를 두 개 생성하여 어떻게 동작하는지 알아보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;xTaskCreate 함수 정의&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32/api-reference/system/freertos.html#task-api&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ESP-IDF 문서&lt;/a&gt;에 정의된 내용에 따르면 &lt;b&gt;xTaskCreate&lt;/b&gt; 함수는 다음과 같이 Parameter를 입력하게 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;static&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;inline&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;BaseType_t&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;xTaskCreate&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;TaskFunction_t&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;pvTaskCode&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #e7f2fa; color: #2980b9; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;char&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;pcName&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #e7f2fa; color: #2980b9; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;usStackDepth&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #e7f2fa; color: #2980b9; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;void&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;pvParameters&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #e7f2fa; color: #2980b9; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;UBaseType_t&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;uxPriority&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #e7f2fa; color: #2980b9; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #2980b9; text-align: start;&quot; href=&quot;https://docs.espressif.com/projects/esp-idf/en/v5.0/esp32/api-reference/system/freertos.html#_CPPv412TaskHandle_t&quot;&gt;&lt;span&gt;&lt;span&gt;TaskHandle_t&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;const&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;&lt;span&gt;pxCreatedTask&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #2980b9; text-align: start;&quot;&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Parameter 정의&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #fcfcfc; color: #404040; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;b&gt;pvTaskCode&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; Pointer to the task entry function. Tasks must be implemented to never return (i.e. continuous loop), or should be terminated using vTaskDelete function.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;b&gt;pcName&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; A descriptive name for the task. This is mainly used to facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default is 16.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;b&gt;usStackDepth&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; The size of the task stack specified as the number of bytes. Note that this differs from vanilla FreeRTOS.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;b&gt;pvParameters&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; Pointer that will be used as the parameter for the task being created.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;b&gt;uxPriority&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; The priority at which the task should run. Systems that include MPU support can optionally create tasks in a privileged (system) mode by setting bit portPRIVILEGE_BIT of the priority parameter. For example, to create a privileged task at priority 2 the uxPriority parameter should be set to ( 2 | portPRIVILEGE_BIT ).&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;b&gt;pxCreatedTask&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; Used to pass back a handle by which the created task can be referenced.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;- pvTaskCode : 실행하고자 하는 함수의 포인터. Task는 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;절대 반환되지 않도록&lt;/span&gt;&lt;/b&gt; 구현되거나(무한 루프) xTaskDelete 함수를 사용하여 종료되어야 한다.&lt;br /&gt;- pcName : Task를 설명하는 이름. 디버깅할 때 유용하게 사용되며 최대 길이는 16 Byte이다.&lt;br /&gt;- usStackDepth : Byte로 지정된 Task의 Stack 크기.&lt;br /&gt;- pvParameters : 생성되는 Task의 매개변수(Parameter)로 사용될 포인터&lt;br /&gt;- uxPriority : Task의 우선순위. portPRIVILEGE_BIT를 설정하여 우선순위를 지정할 수 있다.&lt;br /&gt;- pxCreatedTask : 생성된 Task를 참조할 수 있는 Handler&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;xTaskCreate 기본 예제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708103730961&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &quot;freertos/FreeRTOS.h&quot;
#include &quot;freertos/task.h&quot;

TaskHandle_t taskHandle = NULL;

void counterTask(void *args) {
    int count = 0;
    printf(&quot;counter Task Start...\n&quot;);

    while(1) {
        printf(&quot;count : %d\n&quot;, count);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        count++;
        if (count &amp;gt; 10) {
            count = 0;
        }
    }
}

void app_main(void) {
    xTaskCreate(counterTask, &quot;CounterTask&quot;, 4096, NULL, 10, &amp;amp;taskHandle);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이전 강의에서는 app_main 함수에 무한 루프를 생성하여 0부터 10까지 증가시키는 예제를 작성했습니다.&lt;br /&gt;이번 강의에서는 app_main 함수에 구현한 내용을 &lt;b&gt;counterTask&lt;/b&gt;라는 함수에 포함시키고 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;while(1)&lt;/span&gt; 문을 사용하여 무한루프로 실행시켰습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app_main 함수에서 달라진 점은 xTaskCreate 함수를 사용하여 counterTask를 실행시킨다는 점인데요, 위에서 설명한 것과 같이 counterTask 함수를 Task로 생성하는 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1708104045953&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void app_main(void) {
    xTaskCreate(counterTask, &quot;CounterTask&quot;, 4096, NULL, 10, &amp;amp;taskHandle);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용을 살펴보면&lt;br /&gt;xTaskCreate 함수를 사용하여 counterTask 함수를 실행시키고 Task의 이름은 CounterTask로 설정하였습니다.&lt;br /&gt;Stack의 크기는 4096, 우선순위는 10, Task Handler는 taskHandle로 지정하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1708103806173&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;I (0) cpu_start: App cpu up.
I (187) cpu_start: Pro cpu start user code
I (187) cpu_start: cpu freq: 160000000 Hz
I (187) cpu_start: Application information:
I (190) cpu_start: Project name:     count_number
I (195) cpu_start: App version:      1
I (200) cpu_start: Compile time:     Feb 17 2024 02:13:07
I (206) cpu_start: ELF file SHA256:  d5dd2f5179dd4e8a...
I (212) cpu_start: ESP-IDF:          v5.1-dirty
I (217) cpu_start: Min chip rev:     v0.0
I (222) cpu_start: Max chip rev:     v0.99 
I (227) cpu_start: Chip rev:         v0.1
I (231) heap_init: Initializing. RAM available for dynamic allocation:
I (239) heap_init: At 3FC94448 len 000552C8 (340 KiB): DRAM
I (245) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (251) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (258) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (265) spi_flash: detected chip: gd
I (268) spi_flash: flash io: dio
W (272) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (285) sleep: Configure to isolate all GPIO pins in sleep state
I (292) sleep: Enable automatic switching of GPIO sleep configuration
I (299) app_start: Starting scheduler on CPU0
I (304) app_start: Starting scheduler on CPU1
I (304) main_task: Started on CPU0
I (314) main_task: Calling app_main()
counter Task Start...
count : 0
I (324) main_task: Returned from app_main()
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
count : 9
count : 10
count : 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 빌드하여 ESP32-S3 DevModule에 업로드한 결과 위와 같이 숫자가 0부터 10까지 순차적으로 증가하는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 사용하고자 하는 기능을 함수로 구현한 다음 xTaskCreate 함수를 사용하면 원하는만큼 멀티태스킹을 수행할 수 있습니다.&lt;br /&gt;다음 강의에서는 멀티태스킹 활용 + Queue API에 대해 알아보겠습니다.&lt;/p&gt;</description>
      <category>코딩하자/ESP-IDF</category>
      <category>ESP</category>
      <category>ESP-IDF</category>
      <category>멀티태스킹</category>
      <category>아두이노</category>
      <category>오픈소스</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/55</guid>
      <comments>https://09labs.tistory.com/55#entry55comment</comments>
      <pubDate>Mon, 19 Feb 2024 01:10:27 +0900</pubDate>
    </item>
    <item>
      <title>[ESP-IDF] 2. 빌드 시스템 구축하기</title>
      <link>https://09labs.tistory.com/54</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 09LABS 입니다.&lt;br /&gt;저번 강의에서는 개발 환경을 구축하는 방법에 대해 알아봤습니다.&lt;br /&gt;이번 장에서는 빌드 시스템을 구축하는 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESP-IDF 프로젝트는 여러 구성요소가 융합된 형태를 사용하고 있습니다.&lt;br /&gt;예를 들어 온습도 센서를 사용한 웹서버의 경우 아래와 같은 Component들이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Wi-Fi 드라이버&lt;br /&gt;- TCP/IP Stack&lt;br /&gt;- FreeRTOS 운영체제&lt;br /&gt;- Web Server&lt;br /&gt;- Sensor Driver&lt;br /&gt;- Main code&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESP-IDF에서 프로젝트를 컴파일하기 위한 빌드시스템은 프로젝트 디렉토리, 구성요소 디렉토리를 지정해야 합니다.&lt;br /&gt;이를 기반으로 빌드되며 빌드 순서는 Component 빌드 -&amp;gt; Project 빌드 순서로 진행됩니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Build system 구성&lt;br /&gt;&lt;/b&gt;idf.py 에는 프로젝트 빌드를 쉽게 관리할 수 있도록 아래와 같이 세 가지 툴을 사용하여 프로젝트를 관리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CMake&lt;br /&gt;- ninja&lt;br /&gt;- esptool.py&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CMake는 프로젝트를 구성하고 최종 빌드 툴인 ninja와 함께 사용되는 빌드 파일을 생성합니다.&lt;br /&gt;이전 강의에서 프로젝트를 빌드하기 위해서 타겟을 설정하고 아래와 같이 명령어를 입력했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692026877266&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ idf.py build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;idf.py build 명령어에는 아래의 명령어가 압축되어있다고 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692026932237&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ mkdir -p build
$ cd build
$ cmake .. -G Ninja
$ ninja&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. build 디렉토리를 생성합니다.&lt;br /&gt;2. build 디렉토리로 이동합니다.&lt;br /&gt;3. cmake를 사용하여 Ninja 빌드 파일을 생성합니다.&lt;br /&gt;4. ninja를 사용하여 최종 빌드를 실행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 프로젝트 디렉토리에서 위와 같이 입력하면 프로젝트를 빌드할 수 있습니다.&lt;br /&gt;아래에서 빌드를 실제로 진행해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692027341894&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# esp-idf 디렉토리로 이동
$ cd $HOME/esp/esp-idf

# export.sh를 실행하여 환경변수 설정
$ . ./export.sh

# 예제 프로젝트 디렉토리로 이동
$ cd examples/get-started/hello_world

# Target board 설정
$ idf.py set-target esp32

# build 디렉토리 생성 후 이동
$ mkdir build &amp;amp;&amp;amp; cd build

# cmake를 사용하여 Ninja 빌드파일 생성
$ cmake .. -G Ninja

# ninja를 실행하여 프로젝트 빌드
$ ninja

# ninja를 사용하여 프로젝트 플래시
$ ninja flash&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예제 프로젝트 구성&lt;br /&gt;&lt;/b&gt;지금까지 ESP-IDF의 빌드 시스템의 구성과 빌드 방법에&amp;nbsp; 대해 알아봤습니다.&lt;br /&gt;이제 예제 프로젝트를 직접 생성하여 프로젝트를 구성하는 방법에 대해 알아보겠습니다.&lt;br /&gt;기본적으로 프로젝트의 디렉토리 트리 구조는 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692027529012&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- myProject/
             - CMakeLists.txt
             - sdkconfig
             - bootloader_components/ - boot_component/ - CMakeLists.txt
                                                        - Kconfig
                                                        - src1.c
             - components/ - component1/ - CMakeLists.txt
                                         - Kconfig
                                         - src1.c
                           - component2/ - CMakeLists.txt
                                         - Kconfig
                                         - src1.c
                                         - include/ - component2.h
             - main/       - CMakeLists.txt
                           - src1.c
                           - src2.c

             - build/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 프로젝트 디렉토리에는 아래와 같은 구성요소가 포함되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- CMakeLists.txt : 최상위 디렉토리와 각 Component, Main code에는 CMakeLists.txt 파일이 포함되어 있습니다. CMake가 프로젝트 빌드를 하기 위해 사용되며 빌드 시스템이 어떻게 구성되어 있는지 기술되어 있습니다.&lt;br /&gt;- sdkconfig : sdkconfig는 프로젝트 구성 파일이며 &lt;span style=&quot;background-color: #f3c000;&quot;&gt;idf.py menuconfig&lt;/span&gt; 명령어에 의해 생성됩니다. 필수로 포함되어야 하는 파일은 아닙니다.&lt;br /&gt;- bootloader_components : 부트로더에 필요한 구성요소가 포함되어 있으며 필수는 아닙니다. 부트로더를 수정해야 하는 경우 사용됩니다.&lt;br /&gt;- components : 프로젝트에 필요한 구성요소들이 포함되어 있으며 필수는 아닙니다. 예를 들어 프로젝트에 센서 드라이버를 포함하고 싶은 경우 components 디렉토리에 각 구성요소 디렉토리를 생성 후 CMakeLists.txt와 소스코드, 헤더파일을 포함시킵니다.&lt;br /&gt;- main : main 디렉토리는 프로젝트 중심이 되는 소스코드가 포함된 디렉토리 입니다. 따라서 프로젝트에 소스코드가 많이 있는 경우 main 디렉토리에 포함시키기 보다는 기능별로 components 디렉토리에 구성요소 생성하는 것이 좋습니다.&lt;br /&gt;- build : idf.py로 프로젝트를 빌드하는 경우 자동으로 생성되는 디렉토리이며 임시로 빌드 파일이 생성되는 곳입니다. 최종 바이너리 파일도 이 디렉토리에 생성됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예제 프로젝트 생성 및 빌드&lt;br /&gt;&lt;/b&gt;위에서 프로젝트 디렉토리에 포함되어야 하는 구성요소에 대해 알아봤습니다.&lt;br /&gt;이제 간단하게 1초에 한 번씩 숫자를 0부터 10까지 1씩 증가시키며 출력하는 예제를 생성해보겠습니다.&lt;br /&gt;먼저 프로젝트 디렉토리를 생성하고 기본 구성요소를 포함시켜 보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692030088145&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예제 프로젝트 디렉토리 생성
$ cd $HOME/esp/ &amp;amp;&amp;amp; mkdir count_number

# 예제 프로젝트 디렉토리 이동 및 구성요소 생성
$ cd count_number
$ mkdir main
$ touch CMakeLists.txt
$ touch main/CMakeLists.txt
$ touch main/count_number.c&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 실행을 하면 기본적으로 생성해야 하는 구성요소가 생성되며 트리 구조는 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692030146401&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;├── CMakeLists.txt
└── main
    ├── CMakeLists.txt
    └── count_number.c&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 최상위 CMakeLists.txt를 작성해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최상위 CMakeLists.txt 최소 구성요소&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1692030221789&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(count_number)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최상위 CMakeLists.txt에 포함되어야하는 내용은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;span style=&quot;background-color: #f3c000;&quot;&gt;cmake_minimum_required(VERSION 3.16)&lt;/span&gt; : 프로젝트 빌드에 필요한 최소 CMake 버전에 대한 정보입니다. ESP-IDF는 CMake 3.16 이상에서 작동하도록 설계되었기 때문에 위와 같이 작성합니다. 이 줄은 최상위 CMakeLists.txt 파일에서 가장 첫 번째 줄에 위치해야 합니다.&lt;br /&gt;- &lt;span style=&quot;background-color: #f3c000;&quot;&gt;include($ENV{IDF_PATH}/tools/cmake/project.cmake)&lt;/span&gt; : 나머지 CMake 기능을 가져와서 프로젝트를 구성하고 모든 Components를 검색하는 등의 작업을 수행합니다.&lt;br /&gt;- &lt;span style=&quot;background-color: #f3c000;&quot;&gt;project(count_number)&lt;/span&gt; : 프로젝트를 생성하고 이름을 지정합니다. 프로젝트의 이름은 최종 바이너리의 이름으로 사용됩니다. (Ex : count_nubmer.bin, count_number.elf). CMakeLists 파일 하나당 하나의 프로젝트만 정의할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 세 가지 내용은 최상위 CMakeLists.txt에 포함되어야하는 최소 구성요소이니 하나도 빠짐없이 작성해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;main CMakeLists.txt 작성&lt;br /&gt;&lt;/b&gt;main 디렉토리에 생성한 CMakeLists.txt에는 아래와 같이 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692030610122&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;idf_component_register(SRCS &quot;count_nubmer.c&quot;
                    INCLUDE_DIRS &quot;&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main CMakeLists.txt에는 빌드하고자 하는 소스코드, 참조할 헤더파일이 위치한 디렉토리를 정의할 수 있습니다.&lt;br /&gt;만약 소스코드가 여러 개라면 다음과 같이 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692030710987&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;idf_component_register(SRCS &quot;src1.c&quot; &quot;src2.c&quot; &quot;src3.c&quot;
                    INCLUDE_DIRS &quot;&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;main 소스코드 작성&lt;/b&gt;&lt;br /&gt;저는 프로젝트 이름을 count_number로 작성했기 때문에 main 소스코드 파일명도 count_number.c로 생성했습니다.&lt;br /&gt;0부터 10까지 1초에 1씩 증가시키는 소스코드는 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692031201814&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &quot;freertos/FreeRTOS.h&quot;
#include &quot;freertos/task.h&quot;

int count = 0;

void app_main(void) {
    while(1) {
        printf(&quot;count : %d\n&quot;, count);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        count++;
        if (count &amp;gt; 10) {
            count = 0;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 main 코드에는 app_main이라는 함수가 존재하며 이는 C언어에서 main() 함수와 동일한 기능을 수행합니다.&lt;br /&gt;ESP32는 FreeRTOS를 기반으로 구동되기 때문에 stdio.h 뿐만 아니라 두 가지 헤더를 포함시켰습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692031520677&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;freertos/FreeRTOS.h&quot;
#include &quot;freertos/task.h&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESP-IDF에는 ESP 보드에 최적화된 FreeRTOS가 포함되어 있습니다.&lt;br /&gt;우리가 흔히 아는 delay 함수는 ESP에서 사용되지 않기 때문에 전용 함수를 사용해야 합니다.&lt;br /&gt;vTaskDelay 함수는 &lt;span style=&quot;background-color: #f3c000;&quot;&gt;freertos/task.h&lt;/span&gt;에 포함되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;app_main 함수는 메인 함수이기 때문에 따로 태스크를 생성하지 않거나 while loop를 생성하지 않으면 프로그램이 종료됩니다. 따라서 while loop를 생성하여 무한 루프를 구동시키고 1초에 1씩 숫자를 증가시키도록 소스코드를 작성하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692031873094&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while(1) {
    printf(&quot;count : %d\n&quot;, count);
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    count++;

	if (count &amp;gt; 10) {
        count = 0;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;count_number 프로젝트 빌드&lt;br /&gt;&lt;/b&gt;이제 소스코드 작성, CMakeLists.txt 작성이 완료되었으므로 프로젝트를 빌드 후 시리얼 모니터를 실행해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692032024853&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예제 프로젝트 디렉토리로 이동
$ cd $HOME/esp/count_number

# 프로젝트 타겟 설정
$ idf.py set-target esp32

# 프로젝트 빌드
$ idf.py build

# 바이너리 플래시
$ idf.py flash

# 시리얼 모니터 실행
$ idf.py monitor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정상적으로 빌드 후 시리얼 모니터가 실행되면 다음과 같이 표시됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692032089374&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;I (0) cpu_start: App cpu up.
I (187) cpu_start: Pro cpu start user code
I (187) cpu_start: cpu freq: 160000000 Hz
I (187) cpu_start: Application information:
I (190) cpu_start: Project name:     count_number
I (195) cpu_start: App version:      1
I (200) cpu_start: Compile time:     Aug 15 2023 01:37:07
I (206) cpu_start: ELF file SHA256:  f96eb6166a302a91...
I (212) cpu_start: ESP-IDF:          v5.1-dirty
I (217) cpu_start: Min chip rev:     v0.0
I (222) cpu_start: Max chip rev:     v0.99 
I (227) cpu_start: Chip rev:         v0.1
I (231) heap_init: Initializing. RAM available for dynamic allocation:
I (239) heap_init: At 3FC94448 len 000552C8 (340 KiB): DRAM
I (245) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM
I (251) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (258) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM
I (265) spi_flash: detected chip: gd
I (268) spi_flash: flash io: dio
W (272) spi_flash: Detected size(8192k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (285) sleep: Configure to isolate all GPIO pins in sleep state
I (292) sleep: Enable automatic switching of GPIO sleep configuration
I (299) app_start: Starting scheduler on CPU0
I (304) app_start: Starting scheduler on CPU1
I (304) main_task: Started on CPU0
I (314) main_task: Calling app_main()
count : 0
count : 1
count : 2
count : 3
count : 4
count : 5
count : 6
count : 7
count : 8
count : 9
count : 10
count : 0
count : 1
count : 2
count : 3
count : 4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드한 소스코드가 정상적으로 플래싱 되었고 숫자가 0부터 10까지 증가하는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESP-IDF 기반의 프로젝트 빌드시스템의 구성요소에 대해 알아보고 예제 프로젝트를 빌드 &amp;amp; 실행해보았습니다.&lt;br /&gt;아두이노와 달리 프로젝트를 생성하는 부분이 까다롭다고 느껴질 수 있지만 내가 원하는 대로 프로젝트를 구성할 수 있기 때문에 더욱 심도있는 기능을 포함시킬 수 있을 것 같습니다.&lt;br /&gt;다음 강의에서는 ESP-IDF의 멀티태스킹과 유사한 Task 생성 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bySTLn/btsq5cgW4r6/hQsXkCYukxoxDp7w0rOSzk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bySTLn/btsq5cgW4r6/hQsXkCYukxoxDp7w0rOSzk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bySTLn/btsq5cgW4r6/hQsXkCYukxoxDp7w0rOSzk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbySTLn%2Fbtsq5cgW4r6%2FhQsXkCYukxoxDp7w0rOSzk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>코딩하자/ESP-IDF</category>
      <category>ESP</category>
      <category>ESP 빌드시스템</category>
      <category>ESP-IDF</category>
      <category>esp32</category>
      <category>freertos</category>
      <category>빌드</category>
      <category>아두이노</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/54</guid>
      <comments>https://09labs.tistory.com/54#entry54comment</comments>
      <pubDate>Tue, 15 Aug 2023 01:58:30 +0900</pubDate>
    </item>
    <item>
      <title>[ESP-IDF] 1. ESP32 개발환경 구축</title>
      <link>https://09labs.tistory.com/53</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 09LABS 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아두이노와 같은 오픈소스 하드웨어에는 여러 종류가 있고 블루투스를 사용하려면 블루투스를 지원하는 MCU 또는 블루투스 모듈을 사용해야 합니다. 저는 ESP32를 주로 사용하여 개발을 했었는데 아두이노 Framework를 사용하여 개발하다보니 개발에 제한적인 부분이 있었습니다. 무엇보다도 Espressif에서 제공하는 모든 API를 활용할 수 없고 어떻게 동작하는지 알 수 없다보니 직접 스터디를 해봐야겠다는 생각이 들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESP-IDF Programming Guide : &lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1691635110711&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Get Started - ESP32 -  &amp;mdash; ESP-IDF Programming Guide latest documentation&quot; data-og-description=&quot;&amp;copy; Copyright 2016 - 2023, Espressif Systems (Shanghai) Co., Ltd.&quot; data-og-host=&quot;docs.espressif.com&quot; data-og-source-url=&quot;https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html&quot; data-og-url=&quot;https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhDRBZ/hyTBGtHe3b/6weJATaPJzt2j2qWFk40i0/img.png?width=506&amp;amp;height=377&amp;amp;face=0_0_506_377&quot;&gt;&lt;a href=&quot;https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhDRBZ/hyTBGtHe3b/6weJATaPJzt2j2qWFk40i0/img.png?width=506&amp;amp;height=377&amp;amp;face=0_0_506_377');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Get Started - ESP32 - &amp;mdash; ESP-IDF Programming Guide latest documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;copy; Copyright 2016 - 2023, Espressif Systems (Shanghai) Co., Ltd.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.espressif.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 링크는 ESP-IDF 프로그래밍 가이드로 ESP32 계열을 개발할 때 필요한 모든 내용이 담겨있습니다.&lt;br /&gt;우선 개발환경 구축부터 시작해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;준비물&lt;/b&gt;&lt;br /&gt;- ESP32 보드 (ESP32-DevKit, ESP-WROVER-KIT, ESP32-PICO-KIT 등)&lt;br /&gt;- USB 케이블&lt;br /&gt;- 컴퓨터 (OS마다 상이함)&lt;br /&gt;* Eclipse나 VSCode를 사용하는 경우 Extension을 설치하면 더욱 쉽게 개발이 가능합니다. *&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Requirement 설치&lt;/b&gt;&lt;br /&gt;저는 주로 Ubuntu, MacOS를 사용하고 있으며 이를 기준으로 개발환경 구축 방법에 대해 설명하고자 합니다.&lt;br /&gt;* MacOS 사용 시 &lt;a href=&quot;https://brew.sh/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;HomeBrew&lt;/a&gt;를 미리 설치하셔야 합니다.&lt;br /&gt;&lt;br /&gt;&amp;lt;Ubuntu&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691635534745&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;MacOS&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691635576188&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install cmake ninja dfu-util python3&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ESP-IDF 다운로드&lt;br /&gt;&lt;/b&gt;ESP-IDF는 Espressif Github에서 다운로드 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691635796174&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkdir -p ~/esp
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;Tool 설치&lt;br /&gt;&lt;/b&gt;ESP-IDF에는 ESP32 개발에 필요한 Python 패키지, 디버거, 컴파일러 등을 설치할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691635934937&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ~/esp/esp-idf
./install.sh esp32&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 ESP32가 아닌 ESP32-C3나 ESP32-S3와 같은 다른 칩을 사용한다면 아래와 같이 입력합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691635978023&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ~/esp/esp-idf
./install.sh esp32,esp32s3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 칩에 대해 지원하도록 설치하고 싶다면 아래와 같이 입력합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691636033490&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ~/esp/esp-idf
./install.sh all&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;환경변수 설정&lt;br /&gt;&lt;/b&gt;Tool 설치까지 완료했으면 터미널에서 아래와 같이 입력해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691637222970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;. $HOME/esp/esp-idf/export.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 입력하면 환경변수 설정이 완료됩니다.&lt;br /&gt;다만, 매번 부팅해서 입력해주기 귀찮을 때가 있습니다. 이럴 때 alias 명령어를 사용한다면 더욱 손쉽게 환경변수 설정이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691637282634&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;alias get_idf='. $HOME/esp/esp-idf/export.sh'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어를 사용하는 Shell의 profile에 적용해주면 됩니다.&lt;br /&gt;파일명 :&amp;nbsp; &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;~/.profile, ~/.bashrc, ~/.zprofile, ~/.zshrc&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 네개 중 자신이 사용하는 profile 하나에만 적용해주면 됩니다.&lt;br /&gt;적용을 완료하면 터미널 창에서 get_idf 명령어로 환경변수 설정이 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예제 프로젝트 빌드&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;환경변수 설정까지 완료되었으면 예제 프로젝트를 빌드해볼 차례입니다.&lt;br /&gt;먼저 예제 파일을 복사하여 빌드하고자 하는 디렉토리에 복사해줍니다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691990378773&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ~/esp
cp -r $IDF_PATH/examples/get-started/hello_world .&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로젝트 파일을 복사했으면 타겟 보드를 설정하고 menuconfig를 사용하여 프로젝트 설정을 할 차례입니다.&lt;br /&gt;타겟 보드 설정 시 사용하는 Core를 맞게 설정하셔야 합니다. ESP32 Devkit C 또는 ESP32-WROVER와 같이&lt;br /&gt;일반적인 개발보드를 사용하고 있을 경우 &lt;span style=&quot;background-color: #f3c000;&quot;&gt;esp32&lt;/span&gt;로, ESP32-C2, ESP32-S2, ESP32-C3, ESP32-S3와 같이&lt;br /&gt;일반적인 ESP32 개발보드가 아닌 경우 사용하는 Core 이름을 적어주시면 됩니다. (Ex : esp32s3)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1691991547683&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ~/esp/hello_world
idf.py set-target esp32
idf.py menuconfig&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUhNwf/btsrf4aAZKT/i7QgflbEdvhD7jedc5jh31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUhNwf/btsrf4aAZKT/i7QgflbEdvhD7jedc5jh31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUhNwf/btsrf4aAZKT/i7QgflbEdvhD7jedc5jh31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUhNwf%2Fbtsrf4aAZKT%2Fi7QgflbEdvhD7jedc5jh31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;785&quot; height=&quot;381&quot; data-origin-width=&quot;785&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;menuconfig까지 진입을 완료하면 위와 같은 화면을 볼 수 있습니다.&lt;br /&gt;지금은 추가적인 설정이 필요하지 않으니 esc를 눌러서 종료하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스코드를 빌드하기 위해서 아래와 같이 입력하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691992028628&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ idf.py build
Running cmake in directory /path/to/hello_world/build
Executing &quot;cmake -G Ninja --warn-uninitialized /path/to/hello_world&quot;...
Warn about uninitialized values.
-- Found Git: /usr/bin/git (found version &quot;2.17.0&quot;)
-- Building empty aws_iot component due to configuration
-- Component names: ...
-- Component paths: ...

... (more lines of build system output)

[527/527] Generating hello_world.bin
esptool.py v2.3.1

Project build complete. To flash, run this command:
../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello_world.bin  build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin
or run 'idf.py -p PORT flash'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드가 정상적으로 완료되면 단말에 flash를 하라는 내용을 확인할 수 있습니다.&lt;br /&gt;idf.py를 사용하면 두 가지 방법으로 flash가 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;span style=&quot;background-color: #f3c000;&quot;&gt;idf.py flash&lt;/span&gt;&lt;br /&gt;2. &lt;span style=&quot;background-color: #f3c000;&quot;&gt;idf.py -p &amp;lt;PORT&amp;gt; flash&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ESP32 개발보드를 사용할 때 여러 장비를 한꺼번에 연결하여 사용할 수도 있으니 Serial Port 이름으로&lt;br /&gt;구분지어 업로드를 할 수 있습니다. 만약 한 대만 연결하여 사용할 경우 첫 번째 명령어로 flash가 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1691992375404&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ idf.py flash
...
esptool.py --chip esp32 -p /dev/ttyUSB0 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB 0x8000 partition_table/partition-table.bin 0x1000 bootloader/bootloader.bin 0x10000 hello_world.bin
esptool.py v3.0-dev
Serial port /dev/ttyUSB0
Connecting........_
Chip is ESP32D0WDQ6 (revision 0)
Features: WiFi, BT, Dual Core, Coding Scheme None
Crystal is 40MHz
MAC: 24:0a:c4:05:b9:14
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Compressed 3072 bytes to 103...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.0 seconds (effective 5962.8 kbit/s)...
Hash of data verified.
Compressed 26096 bytes to 15408...
Writing at 0x00001000... (100 %)
Wrote 26096 bytes (15408 compressed) at 0x00001000 in 0.4 seconds (effective 546.7 kbit/s)...
Hash of data verified.
Compressed 147104 bytes to 77364...
Writing at 0x00010000... (20 %)
Writing at 0x00014000... (40 %)
Writing at 0x00018000... (60 %)
Writing at 0x0001c000... (80 %)
Writing at 0x00020000... (100 %)
Wrote 147104 bytes (77364 compressed) at 0x00010000 in 1.9 seconds (effective 615.5 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
Done&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flash가 완료되면 Done이라는 단어를 볼 수 있습니다. 이는 빌드 후 펌웨어 파일이 정상적으로 업로드 되었음을 의미합니다&lt;br /&gt;업로드가 완료되었으면 Hello World 예제가 잘 돌아가는지 확인할 차례입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ESP Monitor 실행&lt;br /&gt;&lt;/b&gt;지금까지 idf.py 를 사용하여 프로젝트 설정, 프로젝트 빌드, 플래시까지 진행해봤습니다.&lt;br /&gt;플래시가 정상적으로 완료되었으면 putty와 같은 시리얼 터미널에서 출력되는 정보를 확인할 수 있습니다.&lt;br /&gt;idf.py에는 시리얼 터미널과 같은 역할을 하는 monitor 기능이 포함되어 있습니다.&lt;span style=&quot;background-color: #f3c000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;span style=&quot;background-color: #f3c000;&quot;&gt;idf.py monitor&lt;br /&gt;&lt;/span&gt;2. &lt;span style=&quot;background-color: #f3c000;&quot;&gt;idf.py -p &amp;lt;PORT&amp;gt; monitor&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;위와 같이 입력하면 monitor 기능을 실행할 수 있습니다.&lt;br /&gt;펌웨어 파일이 정상적으로 업로드 되었으면 아래와 같은 화면을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692025096180&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
I (290) sleep: Configure to isolate all GPIO pins in sleep state
I (297) sleep: Enable automatic switching of GPIO sleep configuration
I (304) app_start: Starting scheduler on CPU0
I (309) app_start: Starting scheduler on CPU1
I (309) main_task: Started on CPU0
I (319) main_task: Calling app_main()
Hello world!
This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision v0.1, 2MB external flash
Minimum free heap size: 390184 bytes
Restarting in 10 seconds...
Restarting in 9 seconds...
Restarting in 8 seconds...&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 ESP32에 예제 프로젝트를 빌드하여 업로드하고 시리얼 터미널로 출력하는 방법에 대해 알아봤습니다.&lt;br /&gt;아두이노 IDE를 사용하면 편하게 빌드하고 업로드할 수 있지만 조금 더 심도있는 기능을 사용하기 위해선 ESP-IDF를&lt;br /&gt;사용하는 것도 좋은 방법이라고 생각됩니다.&lt;br /&gt;다음 강좌에선 기본 빌드 시스템을 구축하는 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2ZSOj/btsrgoUGpbZ/0HjXCFF9OSIVHcYnM4JM0K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2ZSOj/btsrgoUGpbZ/0HjXCFF9OSIVHcYnM4JM0K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2ZSOj/btsrgoUGpbZ/0HjXCFF9OSIVHcYnM4JM0K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/2ZSOj/btsrgoUGpbZ/0HjXCFF9OSIVHcYnM4JM0K/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;400&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>코딩하자/ESP-IDF</category>
      <category>ESP</category>
      <category>ESP-IDF</category>
      <category>esp32</category>
      <category>블루투스</category>
      <category>아두이노</category>
      <category>오픈소스</category>
      <category>오픈소스하드웨어</category>
      <category>하드웨어</category>
      <author>Mcrane</author>
      <guid isPermaLink="true">https://09labs.tistory.com/53</guid>
      <comments>https://09labs.tistory.com/53#entry53comment</comments>
      <pubDate>Tue, 15 Aug 2023 00:02:13 +0900</pubDate>
    </item>
  </channel>
</rss>