', { cookie_domain: 'auto', cookie_flags: 'max-age=0;domain=.tistory.com', cookie_expires: 7 * 24 * 60 * 60 // 7 days, in seconds }); '분류 전체보기' 카테고리의 글 목록 :: MakerLee's Workspace
728x90

쌍안경을 들고 탐조를 하다 보면 사진을 찍어 기록으로 남기고 싶어집니다. 

 

그렇다고 별도로 디지털 카메라 들고다니기엔 동네탐조나 하는 제게는 맞지 않죠. 

 

 

이런 물건을 하나 사서 써 보았는데 생각보다 불편한 점이 많았습니다. 

 

 

 

 

 

 

두꺼워서 잘 잡아주질 못하고 

붙여놓은 채로는 쌍안경을 눈으로 보질 못하니 새를 찾기엔 번거롭더군요. 

쓰다 보면 느슨한 부분이 점점 풀어집니다. 

 

그래서 아예 전용 어댑터를 만들기로 마음 먹었습니다. 

 

 

 

 

 

 

 

 

 

 

자석으로 바로 탈착이 가능하게 만들었습니다. 

핸드폰을 떼자 마자 바로 육안으로 관찰 가능하고 바로 핸드폰을 붙여 짧은 시간 안에 촬영이 가능합니다. 

 

 

 

 

 

https://www.youtube.com/watch?v=qKMaETC3HOA

 

 

 

 

728x90
728x90

3달 하고도 보름만의 meshstatic 포스팅이네요

 

원래는 사실 6월 말에 기기를 설치하고 테스트를 해 보려 했습니다. 

 

그런데.. 설치하자 마자 기기가 먹통이 되었네요?

이미 더위에 접어들어 땀을 줄줄 흘리면서 한시간 동안 고생했는데 저걸 다시 떼낼 엄두가 안 나더라고요

그래서 날이 시원해지면 다시 작업해야 겠다 하고 미뤘습니다. 

 

그런데 날이 시원해지기까지 3달이 넘어갈 줄은 몰랐죠

 

 

 

 

 

 

 

 

 

원래는 걸어서 20분 정도의 거리인데 이번에는 복구한 전동 킥보드로 쓩 하고 다녀왔습니다. 

 

 

 

 

 

 

 

 

겉의 먼지를 제외하면 내부는 깨끗하고 문제가 없었습니다. 

 

 

 

 

 

 

배터리도 별 문제 없군요.

 

 

 

 

 

 

 

 

고장 원인을 찾아보니 어이없게도 전원 스위치의 불량이었네요.

몇년씩 묵은 오래 된 스위치다 보니 내부 접점이 산화된 것 같습니다. 

스위치를 제거하고 납땜으로 연결해보니 문제없이 잘 켜집니다. 

이제 다시 조립해서 도로 설치하면 본격적으로 테스트를 할 수 있을 것 같습니다. 

 

728x90
728x90

기존 타이어는 너무 심하게 닳아 안전이 우려되는 관계로 새 타이어를 주문했습니다. 

기존 타이어는 칼로 잘라 분리했습니다. 

 

 

 

 

 

하지만 손이나 드라이버 등으로 끼우는건 어림도 없더군요

 

 

 

 

 

 

전용 공구를 설계해서 출력했습니다.

너트를 조이면 밀대가 옆으로 밀려나오면서 타이어를 밀어주는 구조입니다. 

 

 

 

 

 

 

 

 

한 5mm 정도만 너 돌리면 되는 상황에서 구조물이 파괴되기 시작했습니다. 

보강해서 재출력해도 되지만 m3 볼트로 조이도록 했더니 볼트 피치가 0.5mm라 렌치로 너트 조이는 데만 30분은 걸립니다. 

 

 

 

 

 

 

 

단순무식하게 하는게 제일인 듯 싶습니다. 

외각 구조물을 튼튼하게 만들어 출력하고 철망으로 보강까지 했습니다. 

이걸 지지대로 삼아 호스밴드로 조여서 타이어를 늘립니다. 

 

 

 

 

 

 

 

 

쉽게 끼워졌습니다. 

호스밴드는 그리스를 살짝만 발라주면 쉽게 뺄 수 있습니다. 

 

 

 

 

 

 

 

 

일단 기존 볼트들은 전부 보안용으로 쓰이는 별볼트라 분해조립시 매우 불편합니다.

전부 일반 육각렌치너트로 교환했습니다.

볼트들은 전부 록타이트를 발라 고정하며, 방수가 필요한 곳은 오링을 끼워 조였습니다. 

 

 

 

 

 

 

 

 

조립을 하고 나서 충전을 해줬습니다. 

 

 

 

 

 

지하주차장에서 시험주행.

 

 

 

 

 

 

 

공유킥보드용 QR 플레이트가 박혀있던 것을 떼고 연락처와 번호를 출력했습니다. 

같은 기기를 여기저기 두고 쓸 것인데다 가족들과 공유도 해야 하기 때문에 기기를 구별해야 하기 때문입니다. 

 

 

 

 

 

 

 

당연히 있을 거라 생각했지만 나인봇 ES 시리즈는 잠금장치가 없더군요.

핸드폰과 연결된 상태에서는 앱으로 잠금을 걸 수 있고 이때는 기기를 조작할 수 없지만 

블루투스가 끊긴 상태에서는 그냥 아무나 전원을 켜고 끌고 갈 수 있습니다. 

현재는 자물쇠를 주문해 놓은 상태입니다. 

728x90
728x90

도색 준비를 합니다. 

 

 

 

 

 

차량용 페인트 프라이머 - 본 도색 - 투명 순으로 칠할 생각입니다. 

 

 

 

 

 

 

중간에 말벌 한마리가 쉬러 왔습니다. 

 

 

 

 

 

 

 

 

 

 

 

 

스프레이질을 오랫만에 했더니 감이 좀 많이 떨어졌더군요. 

끝부분에 뭉치고 흘러내린 자국이 좀 생겼습니다. 

 

밖에서 빠르게 끝낸다고 본 도색을 1회 했더니 클리어 마감후 보니 아쉬운 부분이 있습니다.

본도색도 2회 이상 하는 게 좋았을 걸 그랬습니다. 

 

그래도 조금만 떨어지면 잘 보이지 않는데다 페인트제거부터 여태까지 고생을 너무 많이 해서 이젠 대충 넘기려 합니다. 

이제 타이어 교체만 하면 바로 조립에 들어갈 수 있을 것 같네요

 

 

728x90
728x90

야외에서의 생나무는 1~2년이면 금방 썩기 시작하죠.

 

퀄리티는 괜찮지만 상단 지붕만 페인트칠이 되어 있어 약간 아쉽더군요.

 

 

 

 

 

다이소에서 바니쉬를 샀습니다.

대량작업하기엔  너무 적은 양에 비싼 가격입니다만 새집 한두개 칠하기엔 충분합니다. 

 

 

 

 

 

 

뚜껑도 분리해서 안쪽까지 꼼꼼하게 2번 칠하고 말려줬습니다. 

 

 

 

 

 

 

 

 

 

 

from : https://blog.naver.com/monera/220625932085

 

칠하면서 보니 구멍이 좀 큰 것 같아 검색을 해보니 위와 같은 내용이 나오네요

직구 새집의 입구는 딱 6cm 크기로 다소 큰 편입니다. 

그리고 입구가 약간 높아 유조가 이소할 때 나오기 부담스런 면이 있겠더군요.

 

 

 

 

 

 

 

 

 

조각기로 입구에 홈을 파 주려다가 말았습니다. 

 

 

 

 

 

 

 

그냥 3D 프린터로 유조가 잡을 만한 단을 만들어서 붙여버리는게 훨씬 편하겠단 생각이 들었거든요

 

 

 

 

 

 

 

입구 크기도 여러개로.

입구 위쪽에 비를 가릴 차양도 만들었습니다. 

 

 

 

 

 

 

 

보강이 완료되었습니다. 

 

728x90
728x90

업체명이 그대로 쓰여 있기 때문에 이걸 그냥 타고 다니면 오해를 받을 우려가 있죠.

혹은 다른 사람이 타려고 할 수도 있고요. 

그래서 도색을 싹 벗겨내고 재도색할 생각을 했습니다. 

 

- 다시 생각해보면 그냥 시트지나 씌우고 말아야 했습니다. 따라하지 마세요. 후회합니다. 

 

 

 

 

 

 

페인팅 보조용품을 출력했습니다.

좌우로 끼우고 빙글빙글 돌려가며 칠할 수 있게 만들었습니다. 

 

 

 

 

 

 

살짝 사포질을 해본 결과 이건 아니라는 생각이 들었습니다. 도막이 돌처럼 단단합니다. 

 

 

 

 

 

 

 

 

페인트 리무버를 샀습니다.

사진에 나온 제품은 너무 비싸고, 5천원짜리 국산으로 사도 충분할 것 같습니다. 

 

 

 

 

 

 

 

주차장 구석에서 작업을 시작했습니다. 

페인트 리무버는 처음 써보기에 그냥 뿌려도 보고 위 사진처럼 뿌린 후 랩으로 씌워도 봤습니다. 

랩으로 씌우는게 약간이나마 더 효과가 있는 듯 하긴 합니다만 큰 차이는 없더군요.

 

 

 

 

 

 

빙글빙글 돌려가며 충분히 뿌려서 적셔주면 페인트가 약간 일어나는 걸 볼 수 있습니다. 

업체명 글자는 금방 지워지는데 빨간색 페인트는 화학적으로 다른 제품인 듯 쉽게 벗겨지지 않습니다. 

 

 

 

 

 

 

다만 물러지기는 하기 때문에 어느정도 기다리면 고무같은 느낌이 납니다.

이 때 헤라로 긁어낼 수 있습니다. 

어느정도 긁어내다 보면 리무버가 증발하는지 다시 페인트가 단단해 지는 느낌이 납니다. 

그래서 이 작업을 반복해야 합니다. 

 

 

 

 

 

 

 

 

 

헤라로는 깔끔하게 면을 긁어낼 수 없기 때문에 지저분하게 남습니다. 

추가로 광택기+수세미사포 400번 작업했습니다.

이것도 계속 페인트리무버 뿌려가며 작업해야 하더군요.

 

 

 

 

 

 

페인트 리무버를 한캔밖에 안 샀더니 금방 다 썼네요. 

나머지는 나중에 해야 할 것 같습니다. 

728x90
728x90

버드워칭을 취미 목록에 넣고 가끔씩 쌍안경으로 새 관찰을 하고 있습니다. 

아직 뭐 탐조활동이랄것까진 없고 산책로 근처에서 눈여겨 보는 정도인데요. 

 

 

 

탐조 관련 커뮤니티에서 인공새집 관련 프로젝트를 하는 걸 보고 이것도 관심을 갖게 되었습니다. 

이 프로젝트에 참가하면 새집을 하나씩 받게 되는데 주변 적당한 위치에 설치해 두고 일주일마다 관찰일기를 올리면 됩니다. 

 

프로젝트에 참가하지 않더라도 몇몇 곳에 새집을 설치하고 구경하고 싶은 욕심에 새집을 검색해 봤습니다. 

 

 

 

 

 

 

 

비싸지는 않은데 싸지도 않은 가격.. 

3~4군데 정도 설치장소를 눈여겨 봐 뒀기에 가격은 최대한 싸게 하고 싶어 조금 더 싼 곳을 찾아 봤습니다. 

 

 

 

 

 

 

 

그런 면에서 타오바오만한 곳이 없죠.

몇 가지 모델이 있는데 가격은 고만고만하네요. 

28.8위안이라 6천원도 안 됩니다. 

타오바오 직배 가격이 추가되긴 했는데 이번에 여러개를 같이 묶어서 보낸지라 배송료는 많이 들진 않았습니다. 

보통 배송료가 1~2만원 선이니 배송료를 감안해도 저렴합니다. 

 

 

 

 

 

 

 

 

 

도착한 물건입니다. DIY로 조립식인줄 알았는데 조립되어 왔네요.

상단에는 스테인이 칠해져있고, 나머지는 그을음처리 약하게 되어 있습니다. 

조립은 보다시피 아주 깔끔하게 되어 있는데 목재는 가볍고 약한 종류인 것 같아 스테인 한번 발라주는게 더 좋을 것 같긴 하네요. 

 

 

저렴한 가격에 괜찮은 품질인 것 같아 마음에 듭니다.

겨울쯤에 달아놓고 봄에 관찰해 보려고 합니다. 

728x90
728x90

 

이제 배터리가 어느정도 살아난 ES4의 펌업을 해 줘야 합니다.

펌업 전에는 전원을 켜면 계속 삑삑대고 작동을 할 수 없는 상태입니다. 

 

 

 

 

 

 

분해할 때 잘라냈던 커넥터를 사용합니다. 

저는 아두이노 용으로 쓰는 FTDI232 칩을 사용하는 ISP를 사용했습니다. 

물론 CP2102 도 사용 가능하며 네이버에 CP2102 검색하면 나오는 1~2천원짜리 모듈 사용하면 됩니다. 

 

 

 

 

 

 

노란 선과 초록 선이 TX/RX 이며 검은 선이 GND 입니다. 

 

 

 

 

 

 

 

연결은 처음 분해시 분리했던 모듈의 커넥터에 꽂아주면 됩니다. 

CP2102는 RX/TX가 반대일 수도 있습니다. 

 

 

 

 

 

 

펌웨어 사이트 https://iap.scooterhacking.org/index.html 를 방문해서 

우측 상단의 [Get IAP] 를 클릭해 프로그램을 다운받고 설치합니다. 

 

이후 작업 중에는 배터리와 컨트롤러, 상단 핸들과 하단 모터 등 모든 부품이 연결된 상태여야 하며

전원도 켜진 상태여야 하니 분리된 부품이 있으면 조립후 전원을 켜 줍니다.

 

 

 

 

 

프로그램을 실행 후 ISP가 연결된 시리얼 포트(컴마다 다름)를 선택, 
Source - BLE 선택 후  Connect 버튼 누릅니다. 

Connected가 뜨고 그 아래의 Count 숫자가 올라가면 정상입니다. 

 

 

 

 

 

 

[Flash] 탭의 [Load from repo] 클릭

 

 

 

 

 

 

 

 

차례로 선택. 

 

 

 

 

 

 

이후 [Flash] 버튼 눌러 플래싱합니다. 

 

 

 

 

 

 

 

이제 홈페이지로 가서 [Features] 탭의 중간 부분을 내려 펼치면 링크가 있습니다. 

[Ninebot ESx]를 클릭합니다. 

 

 

 

 

 

 

 

 

법적인 책임에 대한 경고가 나옵니다. 

continue를 눌러 넘어갑니다. 

 

 

 

 

 

 

 

 

 

이제 펌웨어의 옵션을 선택합니다. 

[Presets] 에서 [ES4] 선택. 

 

 

 

 

 

 

 

[Basics] 에서 버전을 선택.

 

 

 

 

 

 

맨 위는(숫자 51575 부분) 모터 파워를 선택하는 부분입니다 

속도와는 상관이 없다고 써 있는데 가속력과 상관이 있는게 아닐까 추측합니다. 

 

두번째는 최고 속도, 세번째는 모터 시작 속도이며

모터 시작 속도는 발로 차며 출발할 때 모터가 작동하기 시작하는 속도를 말합니다

 

그리고 맨 아래 KERS(회생제동) 옵션도 선택합니다. 

 

 

 

 

 

 

 

스로틀을 일정 시간 누르고 있으면 크루즈 컨트롤이 작동하도록 되어 있는데 그 시간을 정합니다. 

 

 

 

 

 

 

 

 

마지막으로 프로그램을 Ninebot IAP로 선택하고 [DOWNLOAD ENC]버튼을 눌러 생성된 펌웨어를 다운로드합니다. 

 

 

 

 

 

 

 

 

 

 

 

이제 Ninebot IAP 프로그램에서 Select file 을 눌러 방금 다운받은 펌웨어 파일을 선택하고 Flash를 누릅니다. 

 

 

 

 

 

 

 

핸드폰에 나인봇 앱을 설치하고 기기의 전원을 켜 보면 바로 연결이 가능합니다. 

 

 

 

728x90
728x90

 

 

 

폐기물품을 파는 분이 있다는 소식을 선배를 통해 정보를 얻고 바로 연락을 했습니다. 

연락후 입금하니 주소를 알려주십니다.

와서 그냥 가져가라 하시더군요.

 

 

 

 

 

 

 

 

 

 

 

 

추석 당일인데도 꽤 밀립니다. 

 

 

 

 

 

 

 

가보니 이렇게 되어있습니다. 

 

 

 

 

 

 

 

적당히 골라서 트렁크에 실으려 했더니 안 실립니다. 

공유킥보드라 접히지 않는 모델이라서 트렁크에 실을 각이 안 나오더군요. 

어쩔 수 없이 뒷좌석에 요리조리 끼워서 넣었습니다. 

 

 

 

 

 

 

돌아오는 길은 엄청나게 밀리더군요.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

필요공구가 많습니다. 

일단 분해용 공구가 필요합니다. 

Torx 렌치-흔히 별렌치라고 불리는 것 중에 가운데 구멍이 뚫린 형태가 필요하고요.

 

 

 

 

추가로 육각렌치, 그리고 보조배터리 팩 분해를 위해 육각렌치도 구멍이 뚫린 형태가 필요합니다. 

십자 드라이버, 펜치 등 기본공구도 있어야 하고요.

 

죽은 배터리를 살리기 위해 가변 파워 서플라이(30볼트 이상 나오는것),

 

그리고 펌웨어 작업을 위해

USB-TTL 어댑터(FT232 혹은 CP2102) 보드,

인두, 납 등이 필요합니다. 

 

이정도 공구가 없으면 고칠 수 없는 물건이더군요. 

 

 

 

 

일단 충전기를 꽂아보면 반응이 없습니다. 

 

 

 

 

 

가운데에 핀이 튀어나와 있는 보안형 별나사입니다. 공구도 당연히 구멍이 뚫린 것이 필요합니다. 

 

 

 

 

 

 

상단의 별볼트와 하단의 볼캡 너트를 풀어주면 배터리 가드가 분리됩니다. 

 

 

 

 

 

배터리 팩이 좀 골치아픕니다. 다른 곳에는 핀형 별볼트를 써 놓고 여기에만 유일하게 핀형 육각볼트를 썼네요

 

 

별렌치로 해보려다 안돼서 볼트제거용 백탭으로 간신히 빼냈습니다.

한두개도 아니고 별도로 공구를 구매하는 게 나을 것 같아서 인터넷을 뒤져봤는데, 국내에서 취급하는 곳을 못 찾았습니다. 

결국 그냥 노가다를 해야 할 듯. 

 

 

 

 

 

 

 

이제 배터리를 살릴 차례입니다. 

전압이 10볼트밖에 안 나옵니다. 

 

 

 

 

 

 

파워 서플라이 선을 대충 끼워주고요

 

 

 

 

 

 

전압을 서서히 올려줍니다.

사진에는 전류가 0으로 표시되는데 어느 정도 전압이 올라가다 보면 전류도 올라가기 시작합니다. 

 

 

 

 

 

 

 

 

 

배터리의 전압이 회복된 것 같아 충전기를 꽂아보았으나 충전중 빨간색과 충전완료 초록색이 번갈아 깜박거립니다. 

나중에 알았는데 조립상태에서만 충전이 정상적으로 되더군요.

 

 

 

 

이제 핸들을 분리합니다. 

보이는 볼트 4개를 제거하면 바로 빠집니다. 

 

 

 

 

커넥터 분리해서 치워둡니다. 

 

 

 

 

 

전면부의 컨트롤러를 제거합니다. 이 부품은 공용 킥보드로 쓰기 위한 회로가 들어 있습니다. 

볼트 홀의 고무 마개를 제거하고 볼트를 풀어 분리합니다. 

회로의 저 초록색 커넥터는 필요하니 챙겨야 합니다. 

 

 

 

 

열어보면 기기의 위치추적을 위한 GPS와 배터리, 신호전송을 위한 모뎀 등이 들어 있습니다. 

유심도 하나 들어 있는데 살아있는건지 모르겠네요. 나중에 따로 확인해 보려 합니다. 

 

 

핸들 하단의 볼트도 분리하고 나면 아래와 같은 모습이 보입니다. 

커넥터를 분리하고 나면 이제 핸들 봉을 분리할 수 있습니다. 

 

 

 

 

 

 

핸들 봉에 있는 볼트들을 모두 풀어줍니다. 

 

 

 

 

 

 

내부의 배터리와 회로에는 위아래로 플라스틱 격벽이 있습니다.

홈에 맞춰 회전시키면 뺄 수 있습니다. 

 

 

 

 

 

 

 

 

 

 

 

 

컨트롤러와 연결되었던 케이블은 고무마개 때문에 잘 안 빠집니다. 

저는 일단 잘라내고 분리했습니다. 

이 전선이 펌웨어 업로드에 쓰이기 때문에 재연결해야 합니다. 

 

 

 

 

 

이 브라켓은 육각 렌치로 고정되어 있는데 고정볼트에 본드를 얼마나 발라놨는지 거의 풀리지가 않네요. 

다행히 한쪽 2개가 풀려서 벌려서 제거할 수 있었습니다만 다른 기기도 이렇게 안 풀리면 어떻게 해야할지 좀 고민입니다. 

 

 

 

 

 

 

 

 

 

이렇게 컨트롤러와 배터리가 분리되었습니다. 

 

 

 

 

 

 

 

 

내부 배터리 역시 전압이 비정상입니다. 

보조 배터리와는 달리 BMS 리셋이 없이는 재작동하지 않습니다. 

 

 

 

 

동그란 창은 LED 상태 표시창입니다.

회로의 내부에는 리셋 스위치가 있는데 뚜껑을 제거하지 않으면 접근이 불가능합니다. 

 

 

 

 

 

리셋 스위치의 위치는 4군데 볼트 홀 중에서 오른쪽 아래에 있는 것과 LED 표시창이 십자로 위치하는 지점입니다. 

이 부분을 인두로 살짝 지지거나 드릴로 뚫어 접근할 수 있다고 합니다. 

 

 

 

 

 

저는 핸드드릴을 사용했습니다. 전동드릴은 회로를 망가트릴 위험이 있으므로 절대 비추천합니다. 

 

 

 

 

 

약간 비뚤긴 했는데 그래도 스위치가 보입니다.

이 스위치를 눌러보면 빨간 LED가 깜박거리는데,

계속 누르고 있으면 7~8초 정도 후에 약간 길게 한번 깜박거리며 리셋이 됩니다. 

 

 

 

 

 

파란색이 들어오면 정상입니다.  다만 배터리 전압에 따라 파란색이 들어오지 않을 수도 있습니다. 

저도 모든 경우를 확인해보지는 못했습니다.  

 

커넥터의 전압 확인해서 30V 이상 나오면 이제 충전이 가능합니다. 

충전중에는 LED가 빨간색으로 깜박거립니다. 

 

 

 

 

이제 배터리와 기타등등 모든 케이블을 다시 연결합니다.

모든 회로가 연결이 되지 않으면 충전이 불가능하더군요.

보조 배터리가 정상인 경우에는 보조 배터리를 꽂고 충전해도 됩니다.

보조 배터리가 비정상인 경우에는 보조 배터리를 제거하고 본체 컨트롤러에 바로 충전잭을 연결해도 됩니다.

 

보조 배터리의 충전구에 충전기를 꽂으면 충전이 되는 것을 볼 수 있습니다. 4~50% 정도 충전후 펌업을 하려 합니다. 

가끔 배터리의 전압이 너무 과하게 낮으면 충전이 제대로 되지 않고 삐 소리가 나며 리셋이 되는 경우가 있습니다. 

삐삐거리는 기기를 몇분간 그대로 둔 후 다시 껐다 켜고 배터리 리셋 스위치를 눌러 리셋시킨 후 충전을 해 보니 정상적으로 되는 경우가 있었습니다. 

 

 

 

728x90
728x90

시계 수리라고는 해도 뭐 대단한건 아니고 그냥 케이스갈이입니다. 

조카가 어렸을 때부터 쓰던 시계가 있는데 고장이 났더군요. 

열어보니 내부 회로가 망가진거라 수리가 불가능합니다. 

어렸을때부터 계속 쓰던거라 추억의 물건이라고 계속 쓰고 싶다고 하길래 타오바오에서 이미지검색으로 같은 물건을 찾았습니다. 

 

 

 

 

 

 

뜯어서 부품을 옮겨줍니다. 

 

 

 

 

 

원래 쓰던 케이스는 몇번 책상에서 떨구는 바람에 금도 가고 볼트기둥도 다 부러졌습니다. 

보강을 해 줍니다. 

 

 

 

 

 

 

볼트기둥은 3D 프린터로 출력후 맞춰서 접착해줍니다. 

 

 

 

 

 

 

 

 

바늘을 다시 끼우고 조립해서 시간을 맞춰줬습니다. 

 

갖다주니 조카가 참 좋아하네요

728x90
728x90

 

저렴하게 구매해서 잔뜩 쟁여둔 시리얼 컨트롤 방식 UBtech 서보가 있습니다. 

프로토콜 분석한다고 해 놓고 초장기로 묵혀두고만 있죠.

 

 

 

 

 

 

다 중고품이라 볼트도 몇개씩 없기도 하고 전부 같은 모델이 아니고 일부는 서로 내부적으로 약간씩 다르기도 합니다.

전체적으로 정비를 하면서 정리를 해 둘 생각이 들었습니다. 

 

 

 

 

 

 

 

 

분해를 해 보니 아무래도 분해하는 김에 싹 다 세척하고 재조립하는게 낫겠다 싶네요.

 

 

 

 

 

 

 

 

디그리서를 살까 하다가 추석연휴라 배송도 안되고 해서 마트에서 라이터 기름을 몇통 사 왔습니다. 

 

 

 

 

 

 

 

 

 

 

다이소에 가서 사각용기를 두개 사왔고요

 

 

 

 

 

 

 

 

프린터로 내부통을 만들고 철망을 끼워 조립한 후 라이터기름을 붓고 흔들었더니.....

밀폐가 되는 통이 아니었습니다.

 

 

 

 

 

 

다이소를 재방문했습니다. 

 

 

 

 

 

 

 

다시 내부망을 만들어 넣고 라이터 기름을 부었습니다. 

 

 

 

 

 

 

 

라이터 기름은 성분이 솔벤트 100%라 유해성도 높고 냄새도 엄청 독합니다. 

살짝 머리가 아파오기 시작해서 가방에 넣고 나와서 주차장 구석에 자리를 잡았습니다. 

1차로 세척을 한 후 다시 깨끗한 라이터 기름에 2차로 세척을 했습니다. 

 

 

 

 

 

 

 

 

세척을 마치고 나니 깨끗하군요

 

 

 

 

 

 

약간씩 남은 찌꺼기는 면봉으로 닦아줬습니다. 

 

 

 

 

 

 

재조립. 

내부 회로의 고장제품도 있을 수 있기 때문에 구리스도 없이 일단 가조립만 해 둡니다. 

 

 

 

 

 

 

모자란 볼트와 베어링 등을 알리에 주문해 뒀습니다. 나중에 회로 점검하면서 하나씩 조립해 둘 생각입니다. 

 

 

728x90
728x90

https://www.youtube.com/watch?v=1OjEtobqbqw

(유튜브 썸네일이 왜 안 뜨지?)

 

탈진기 축 제작하려다 보니 자를일이 많아서 공구를 제작하게 되었습니다. 

만들고 보니 일단 길이조절은 잘 되는데 수정할 부분이 있어 곧바로 다시 버전업을 해야할듯. 

728x90
728x90

 

 

https://smarthomescene.com/guides/convert-xiaomi-lywsd03mmc-from-bluetooth-to-zigbee/

 

Convert Xiaomi LYWSD03MMC BLE Sensor to Zigbee

How to convert the Xiaomi LYWSD03MMC Bluetooth Sensor to Zigbee by flashing a custom firmware Over-the-Air.

smarthomescene.com

 

전에 해커뉴스를 보다가 기록해 둔 뉴스입니다. 

샤오미의 온습도센서를 블루투스에서 지그비로 변경할 수 있다는 것이죠. 

 

블루투스와 지그비는 몇 가지 차이점이 있긴 한데 실사용자 입장에서의 차이점이라면 지그비 허브에 연결해서 상시 추적을 할 수 있고, 메시 네트워크를 구성해서 안정적으로 사용할 수 있다는 점 등이 있겠네요. 

 

프로젝트 Github 은 https://github.com/pvvx/ATC_MiThermometer 입니다. 

깃헙 링크에 보시면 이외에도 같은 칩을 쓰는 많은 기기들이 변경 가능한 것을 알 수 있습니다. 

 

 

 

Home Assistant 에도 붙일 수 있다 하여 지그비 허브를 사 뒀습니다. 

 

 

다만 최근 제품들은 펌웨어가 OTA 변경을 못하도록 변경되어 나오고 있기 때문에 납땜없이 온라인으로만 펌업이 가능할지 불가능할지는 알 수 없습니다. 

다행히 제가 구입한 물건들은 대부분 구버전 펌이었지만 다른 셀러에게 구입한 물건은 일부 신형 펌웨어도 있었는데요. 

이 부분에 대한 내용은 나중에 따로 다루겠습니다. 

 

 

 

 

맨 처음에 쓴 링크로 다시 돌아가서,
OTA 펌웨어는 일단 크롬/엣지/사파리 등에서 enable-experimental-web-platform-features

를 Enable 로 바꾸고 난 뒤. 프로그램을 재실행하고 진행하면 됩니다. 

 

본문에 2가지 방법이 소개되어 있는데  

1. Convert LYWSD03MMC to Zigbee (OTA, devbis)
2. Convert LYWSD03MMC to Zigbee (OTA, pvvx)

가 있습니다. 2번이 좀 더 단순하다고 되어 있어 이쪽을 먼저 해 봤으나 실패하여 1개가 벽돌이 되었고 나머지는 1번 방법을 통해서 진행했습니다. 

 

 

 

 

본문에 다 설명되어 있는 내용이긴 하지만 이미지를 추가해서 다시 정리해보면 아래와 같습니다. 

 

1.브라우저에서 https://pvvx.github.io/ATC_MiThermometer/TelinkMiFlasher.html 로 이동합니다. 

2. Get Advertising MAC을 체크하고 빈칸에 LYWSD03,ATC 를 입력하고 Connect를 누릅니다. 

 

 

 

 

 

3.그러면 뜨는 창에 LYWSD03MMC 혹은 경우에 따라 ATC로 시작하는 기기명이 나오는데 이를 선택하고 페어링 버튼을 누릅니다. 

 

 

 

 

 

4. 잠시 기다리면 위와 같은 화면이 나옵니다. [Do Activation] 버튼을 누르고 기다립니다.

 

 

 

 

[OTA 가 불가능한 신형 펌웨어의 경우 지원 불가능하다는 메세지가 나오며 이 기기는 납땜해서 펌웨어를 직접 다운그레이드 한 후 다시 진행해야 합니다. 이 방법은 추후 따로 포스팅하겠습니다.]

 

 

 

 

 

5. 위와 같은 창이 나오면 [파일 선택] 에서 https://devbis.github.io/telink-zigbee/ 이 링크의 ATC_ota_40000.bin 을 다운받아 업로드하고 [Start Flashing]을 눌러 플래싱을 합니다. 

상단에 업로드 %가 표시되며 100% 가 될 때까지 기다립니다.

 

 

**여기까지의 과정은 단계별로 몇십 초~1분 정도의 시간이 걸릴 수 있으나 상황에 따라 진행이 되지 않고 멈춰 버리기도 합니다. 특히 페어링과 액티베이션 과정에서 가끔 그런 일이 일어나니 이 경우에는 해당 진행을 다시 처음부터 하여야 합니다. 

 

6. 프로세스가 완료되면 기기의 배터리를 분리하고 15~20초 기다립니다. 

 

 

 

 

 

다시 비슷한 과정을 거칩니다. 

7. 이번에는 https://devbis.github.io/telink-zigbee/ 이 주소로 들어갑니다. 

8. Get Advertising MAC 체크 /  LYWSD03,ATC 입력 /  Connect 하여 기기를 페어링합니다. 

9. https://github.com/devbis/z03mmc/releases 에서 z03mmc.bin 을 다운로드 합니다. 

10. [파일 선택] 에서 해당 파일을 업로드하고 플래싱합니다. 

 

 

 

 

 

이제 Zigbee hub 의 제조사 앱으로 들어가서 Zigbee 페어링을 시도해 보면 장치가 뜨고 페어링이 되는 것을 볼 수 있습니다. 

 

 

728x90
728x90

타오바오에서 29위안(5500원 정도)에 구매한 공기질 센서보드입니다. 

사 놓고 보니 괜찮은 듯 해서 몇개 더 사려고 했는데 이미 품절이더군요. 

 

 

 

 

 

 

 

은색의 사각형 센서가 공기질 센서, 아래쪽의 금색 센서는 이산화탄소 센서인 MH-Z19B 이고 

보드 왼쪽 위 구석에 U5 라고 쓰인 작은 센서는 SHT20 온습도 센서입니다. 

 

 

 

 

공기질 센서는 PMS시리즈이긴 한데, PMS7003와 굉장히 닯았지만 공기 배출구의 형상이 달라 분해를 해 보았습니다.

보드에 PM3500 이라고 쓰여 있어 관련 정보를 찾아 보았으나 아무런 결과도 뜨지 않네요. 

 

 

 

하지만 핀아웃은 PMS7003와 같은 듯 해서 그냥 쓰면 될 것 같습니다. 

 

 

 

 

 

이산화탄소 센서의 핀아웃. 

 

 

 

 

정리하면 이렇게 됩니다. SHT20 센서는 I2C 를 이용합니다. 

결국 모든 센서가 개별 핀을 사용하는 것이나 마찬가지라 사용에는 무리가 없어 보입니다. 

 

보드의 오른쪽 아래에는 VOC 센서 자리가 비어 있는데요. 

핀 하나가 좌측의 2핀 커넥터 자리로 연결이 되어 있습니다. 커넥터에는 AD4 라고 쓰여 있죠. 

 

 

 

 

Analog 값을 출력하는 VOC 센서를 찾아보니 아마도 TG2600 인 것 같습니다. 

알리에서 5000원 정도 하는 가격으로 판매하니 이것까지 사용하면 만원 약간 넘는 정도에 풀세팅으로 공기질 측정이 가능하니 괜찮을 듯 하네요. 

 

 

728x90
728x90

 

기타용 프리앰프 케이스. 

돈 들이긴 싫고 해서 알리에서 저렴한 모듈 사다가 9V 배터리와 커넥터 연결해서 제작. 

음질이 약간 아쉽긴 한데 기능적으로는 원하는 대로 동작하기 때문에 그냥 쓰기로 합니다. 

 

 

 

 

 

 

 

필라멘트 스풀 리와인더. 

메이커월드 등에 기어를 이용한 제품이 있긴 하지만 써보니 공간도 많이 차지하고 속도도 느려 드릴에 사용할 목적으로 만들었습니다. 

사용시에 약간 요령이 필요하긴 한데 빠르게 감을 수 있어 좋네요. 

 

 

 

 

 

드릴 케이스.

탈진기 때문에 드릴을 0.1mm 단위로 구비해 놓았더니 정리가 안 되어서 제작했습니다. 

글씨와 라벨을 넣느라 시간을 버리고, 미세조정하느라 시간을 버리고 하다 보니 주말을 거의 이걸로 보냈군요. 

그런데 1.7mm 드릴날은 어디다 잃어버렸는지 모르겠네요. 

728x90
728x90

너무너무 오랫동안 잘 써왔던 구형 엑박패드가 슬슬 수명의 한계를 보이더군요

인터넷에서 평이 좋던 8bitdo 컨트롤러를 구매해 봤는데 딱히 더 좋지도 않고 윈도우에서 연결과 매핑도 깔끔하게 되질 않네요.

그래서 빠르게 중고판매하고 바로 엑박패드 4새대를 구매했습니다.

여전히 구관이 명관. 

728x90
728x90

기존 설계의 문제는 힘이 가해졌을 때 이스케이프 휠에 팰릿이 잠겨서 움직이지 않기 때문에 밸런스 휠을 손으로 한번 흔들어 줘야 움직임이 시작된다는 것이었습니다. 

 

 

 

그러던 중 팔로우하고 있던 일본 작가분의 작품을 보게 되었는데요

https://x.com/BellTreeNursing

이 작품을 출력해서 움직여 보니 제것과 달리 힘만 주면 바로 작동을 하더군요

 

 

 

 

 

원인을 찾다 보니 펠릿 쥬얼의 각도가 문제였습니다. 

기계식 시계에서는 진짜 쥬얼을 쓰지만 제 물건은 그냥 플라스틱 덩어리일 뿐이라 마찰계수가 달라서 작동을 하지 않는 거였습니다. 

각도를 수정해 가며 여러 번 출력해 가며 부드럽게 움직이는 각도를 찾았습니다. 

 

 

 

 

 

밸런스 휠과 스프링도 약간 수정했습니다. 

 

 

 

 

https://www.youtube.com/watch?v=SOrmzYx_KAM

이게 그 결과입니다. 

 

 

 

 

 

 

탈진기의 중심 부분은 어느정도 완성이 된 것 같아 주변 기어와 태엽을 추가하려고 계속 작업중입니다. 

주변에 기어와 축이 많이 추가되다 보니 축의 길이를 정밀하게 절단해야 할 일이 많더군요.

 

 

 

 

 

3d 프린트 뚜르비옹을 만들었던 유튜브의 @mechanistic3d 의 작업중 좋아 보이는 것이 있어 따라했습니다. 

 

https://www.youtube.com/watch?v=iwKXmwjGt9U

 

 

 

절단작업을 해 보니 훨씬 편리하긴 한데 좀 더 정밀한 작업을 위해선 수정할 부분이 있네요. 

 

 

 

 

 

 

728x90

'Making > 탈진기 설계와 제작' 카테고리의 다른 글

두번째 설계한 탈진기 테스트  (0) 2024.04.16
새 탈진기 설계와 조정.  (0) 2024.04.04
탈진기 첫 테스트.  (0) 2024.03.01
포크와 롤러 설계  (0) 2024.02.25
팔레트 설계  (0) 2024.02.25
728x90

구매한 지는 꽤 되었는데 리뷰가 늦었네요. 

 

올해 초 E3D 사의 Rapidchange Revo 가 Bigtreetech 사와의 협업으로 뱀부랩용 제품으로 출시되었습니다. 

 

 

제가 최근에 탈진기 등의 작업을 하다 보니 정밀한 출력이 필요했고 그에 따라 0.2mm 노즐 등을 바꿔 사용하곤 했습니다. 

당연하게도 노즐 교환의 귀찮음이 심각하게 다가와서 이 제품이 눈에 들어왔고요. 

저는 3월 말 쯤 구입하여 써보게 되었는데요. 

 

 

 

 

문제는 Revo 노즐은 0.4mm / 0.6mm 는 똑같이 있으면서 미세 노즐은 0.25mm / 0.15mm 라는 이상한 규격을 만들어서 사용한다는 것이었습니다. 

그리고 이 노즐은 뱀부랩 스튜디오에서 지원하지 않습니다. 

 

바쁜 일이 많아서 이걸 어떻게 하질 못하고 그냥 0.4 / 0.6 노즐만 사용하고 있었는데 이것만 해도 상당히 편하더라고요.

그래서 P1S 용까지 추가구매를 했습니다. 

 

 

 

최근에 좀 여유가 생겨서 다시 검색을 해 보니 다행히 OrcaSlicer에서 편집이 가능하다고 하더라고요. 

Makerworld 에서 'revo profile'로 검색을 해 보면 anselor 라는 유저가 만들어 놓은 프로파일이 있어 고생을 많이 덜었습니다. 

 

 

다만 Orcaslicer 최신 버전을 사용해 보니 뱀부랩 스튜디오처럼 노즐 프로파일과 저장된 노즐이 다르다며 출력이 불가능하더군요. 

오르카슬라이서 2.1.0버전을 써야만 출력을 할 수 있습니다. 

 

 

 

benchy를 30% 축소해서 0.15mm 노즐로 출력해 봤습니다.

깔끔하게 잘 나오는 편입니다만 진동에 의한 물결무늬가 좀 더 잘 보이긴 합니다. 

728x90
728x90

 


뱀부랩 카페에서 알게 된 곳인데 타오바오 필라멘트 셀러 중에 R3D 라는 곳이 있습니다. 

그런데 불량재고를 16개씩 묶어서 굉장히 저렴하게 판매한다더군요. 

구매한 분들 리뷰를 보니 퀄리티도 나쁘지 않고요. 

 

 

 

 

 

 

링크 : https://detail.tmall.com/item.htm?id=742776751219

지금은 이미 재고가 많이 나가 많이 줄었습니다만 16롤 묶음판매는 여전히 판매는 하고 있습니다. 

사진의 마우스 커서가 위치한 물품이 그것입니다. 

색깔과 종류를 불문하고 PLA/PETG 를 섞어서 16롤을 320위안(=61000원) 에 판매합니다. 

 

사실 지난번에 한번 구매를 해 봤는데, PLA/PETG 반반에 흰색부터 핑크색에 투명에 목분PLA도 하나 섞여있고 진짜 랜덤입니다. 

진공은 풀려있는 경우가 좀 있는데 그래도 퀄리티는 대부분 정상이더군요. 

저같이 PLA/PETG 돌아가면서 사용하는데다 색은 별로 중요하지 않고 사용량이 많은 사람에게는 정말 좋더군요. 

 

 

 

 

 

 

 

 

그래서 한번 더 샀다는 이야기입니다. 

방엔 둘 데가 없어서 트렁크에 실어뒀습니다. 

 

 

 

728x90

'주인장 잡담' 카테고리의 다른 글

탐조일지 #1 - 동네탐조  (0) 2024.06.06
탐조책방 방문기  (0) 2024.05.25
Arduino IDE의 ESP 보드 컴파일 에러 문제 해결  (0) 2024.05.03
새 차 고르기 #2  (0) 2024.03.20
새 차 고르기 #1  (0) 2024.03.17
728x90

OLED 통합한다고 해놓고 한참 걸렸네요.

부품 수급과 드라이버 회로 테스트하고 이것저것 하다보니 많이 늦었습니다. 

 

처음 만든 회로는 실패하는 바람에 다시 한번 관련 자료를 찾아 회로를 수정하고 부품을 수급하고 테스트 과정을 거쳤습니다. 

관련 포스팅 : https://pashiran.tistory.com/1375

 

 

 

 

 

 

 

 

 

 

 

 

실크스크린을 이용해 납을 올리고 핀셋으로 하나하나 부품을 올려줍니다. 

 

 

 

 

 

저는 오븐이 아니라 핫 플레이트를 사용하는지라 앞면에 부품이 납땜된 후에 뒷면에 부품을 올리기 어렵습니다. 

그래서 급하게 솔리드웍스에서 지그 설계를 하고 출력해 사용했습니다. 

 

 

 

 

 

 

이후 뒷면은 히팅 건으로 가열해서 마무리를 해 줍니다. 

 

 

 

 

 

 

아두이노 부트로더를 올려줍니다. 

 

 

 

 

아두이노 나노를 베이스로 삼았기 때문에 위와 같이 세팅하고 부트로더를 올려주면 됩니다.

저는 아두이노에 arduino as isp 스케치를 올려 프로그래머로 사용하기에 [Programmer :"Arduino as ISP"] 를 선택했습니다. 

 

 

 

 

부트로더가 올라간 보드에 간단하게 blink 스케치를 약간 편집해 넣었습니다.

업로드해서 테스트해보면 잘 되는 것을 볼 수 있습니다. 

 

 

 

 

U8glib 예제를 넣어봤습니다. OLED도 잘 되는군요. 

점검해 보니

1. USB 커넥터를 Bottom으로 보내야 겠고

2. Reset 스위치를 제거했더니 쓰기가 불편해서 다시 넣어야 할 것 같습니다. 

3. OLED 위치도 약간 조정이 필요하네요.

 

 

 

[진짜진짜_마지막_최종] 수정 버전의 PCB를 주문했습니다. 

주문한 PCB가 올 때까지는 기존 보드를 사용하면서 스케치를 수정하려 합니다. 

728x90
728x90

여느 때처럼 타오바오 중고물품 순회를 하다가 이런 걸 발견했습니다. 

 

 

 

 

 

도착한 물건을 조립해 보니 괜찮아 보입니다. 

태양광 패널의 고정이 확실치 않아 바람이 세게 불면 돌아갈 것 같긴 한데요. 

 

 

 

 

 

 

 

볼트 너트가 포함이긴 한데 와셔를 추가하고 렌치볼트를 쓰는 등 갖고 있던 재료로 업그레이드를 했습니다. 

 

 

 

 

 

 

 

배터리는 무려 10Ah.

충방전도 잘 됩니다. 

문제는 리튬인산철 배터리란 거죠.

 

 

 

 

 

 

 

제가 스무개나 만들어 놓은 충방전 회로는 리튬이온 용인데 말이죠

 

 

 

 

 

 

이 문제는 일단 넘어가고

분해해 보니 방수 패킹도 잘 되어있고 공간도 나쁘지 않아 보입니다. 

LED 패널은 필요없으니 제거합니다. 

 

 

 

 

 

 

 

태양광 패널도 10W 라 나쁘지 않아 보이네요

 

 

 

 

 

 

 

 

안테나 케이블을 상단에 설치하려 구멍을 뚫었는데 뚜껑을 닫아보니 높이가 살짝 높아서 안 닫히는군요. 

하단으로 옮겼습니다. 

 

 

 

 

 

 

 

배터리를 넣고 위쪽에 회로를 넣으면 딱 맞을 것 같습니다. 

728x90
728x90

노드를 하나 외부에 설치할 계획을 세우고 나니 더욱 많은 문제가 있습니다. 

 

1. 기술적 문제

-노드는 태양광으로 자체적으로 돌아가야 합니다. 

태양광 패널과 충전 시스템, 배터리로 구동되며 방수 케이스에 넣어져 환경으로부터 보호되어야 하죠. 

기술적 문제들은 스스로 해결할 수 있긴 하지만, 각각에 대해 추가 비용이 들어간다는 점은 상당히 부담이 됩니다. 

 

2. 환경적 문제

-태양광 패널은 그림자가 지지 않는 노출된 곳에 설치되어야 합니다. 

개인이 접근할 수 있는 곳에서 이런 위치를 찾기는 쉽지 않습니다. 

-또한 전파의 특성상 가능한한 높은 곳에 설치되어야 합니다. 

 

3. 법적 문제

위와 같은 사항을 따르려 하면 고층 빌딩을 여러 개 갖고 있는 엄청난 건물주가 아닌 이상, 

서울의 야산 등에서 적당한 설치 위치를 찾아야 합니다. - 다른 방법이 있다면 알려주세요

공유지에 개인 물건을 설치하는 것은 당연히 법적 문제가 따릅니다. 

 

동네 야산의 휴게 위치 등에는 동네 주민들의 물건들도 놓여진 경우가 많아 크게 문제가 되진 않을 것 같습니다만, 

엄밀하게 따지자면 경범죄에 속할 수밖에 없는 게 사실이겠죠.

 

허가를 얻는 것도 방법입니다만, 사업자도 아니고 개인이 이런 물건을 설치하겠다고 하면 과연 허가가 날까요?

 

4. 기타 문제

설치 위치를 시뮬레이션 해 보면 손이 닿는 높이(1.5m정도) 에 설치하는 것은 시각적으로 문제가 될 수 있습니다. 

적어도 2~2.5m의 높이에 설치해야 위화감이 없을 것 같습니다. 

결론적으로 동네 야산을 사다리까지 짊어지고 올라가야 하며, 사다리 구매 비용은 별도라는 문제가 있습니다. 

 

 

728x90
728x90

강아지 산책하는 김에 여기저기 새가 보이면 기록을 해보려 합니다. 

아무래도 산책길 특성상 참새,까치,직박구리,비둘기가 99%이긴 한데요

그래도 운 좋으면 하나씩 늘릴 수 있지 않을까 합니다. 

 

직박구리

 

 

 

 

 

까치. 

요즘은 어린 새들이 많아서 경계심이 적어 근처까지 막 오고 그러네요

 

 

 

 

 

 

한강 산책중 박새랑 참새들이 계속 왔다갔다 하며 시끄럽게 굴길래 봤더니 스프링클러 틀어놓은 곳에서 샤워하느라 정신없더군요. 

 

 

 

 

 

청둥오리 수컷. 암컷과 새끼들도 있었는데 카메라 맞추는사이 사각으로 사라졌네요.

 

 

 

 

 

 

 

 

 

새끼 까마귀인가? 했던 대륙검은지빠귀

저번에도 한번 봤었는데 사진을 못 찍었고 이번에는 사진을 찍어 도감에서 자세히 찾아봤습니다. . 

몸 전체가 검은색이고 부리와 눈가가 노란색. 직박구리보다 약간 큰 정도에 몸은 더 통통. 

낙엽을 파헤치며 지렁이 찾아 먹는중이었습니다. 

 

 

 

 

 

그리고 안타까운 사건 2가지.

새끼까치 한마리 죽어가는 것 발견. 

그동안 몇번 까치를 구조한 경험은 있으나 첫 발견시부터 살 수 있을지 모르겠을 정도로 매우 약한 상태였는데요. 

물과 음식을 조금씩 급여했으나 몇시간 뒤 사망했습니다. 

 

 

 

 

 

 

도로 인근 분수대. 사람이 거의 찾지 않는 곳인데 이상하게 물까치들이 시끄럽게 날아다니더군요. 

분수를 한바퀴 돌다 보니 물까치가 한마리 죽어서 떠있었고요. 

아마도 분수대 위에 앉아 있다가 분수의 갑작스런 분출에 맞아서 물에 빠진 뒤 나오지 못한 것으로 추정합니다. 

건져서 물까치들이 **장례식을 치를 수 있도록 한쪽에 두고 나왔습니다. 

 

**새들도 죽은 동료가 있으면 주변 여러 마리의 새들이 한참동안 추모하듯 시끄럽게 모여서 울곤 합니다. 

 

 

 

 

일단 쌍안경에 핸드폰 카메라 맞추는 건 어떻게 좀 개선을 해야 할 것 같네요. 

728x90
728x90

0.96" 와 같이 구매했던 1.3" OLED입니다. 

첫번째 것이 구동했으니 이것도 당연히 될 것 같지만 그래도 테스트를 하지 않고 넘기기엔 뭔가 찜찜해서 작업을 합니다. 

 

이제는 노안이 심해져 현미경의 도움이 필수에요. 

 

 

 

 

 

30핀을 일일이 하나하나 선을 까서 납땜합니다.  

 

 

 

 

 

 

 

 

 

0.96" 와 1.3" 두개 했더니 한나절이 후딱 지나가네요

좌측 0.96" 는 사실 다른 곳에서 떨이로 산거라 드라이빙 칩이 뭔지 모릅니다. 

그냥 SH1106 기준으로 납땜해서 동작시켜 보고 안되면 버릴 생각입니다. 

 

 

 

주변 회로를 연결하고 납땜을 해 봤는데 동작을 안 하네요.

주말내내 이 작업만 했는데 뭔가 잘못된 부분 찾는것도 힘들어 그냥 기존 OLED 모듈을 하나 잡았습니다. 

 

뒷면의 OLED 연결을 떼어냈습니다. 

 

 

 

 

 

그리고 1.3" 모듈을 붙여 다시 납땜했더니 동작합니다. 

이 작업은 이걸로 마무리를 하려 합니다. 

이제 회로 구성해서 스탑된지 반년이 넘어가는 디스펜서 작업을 계속 해야겠습니다. 

 

728x90
728x90

예전부터 회로를 제작할 때 별도의 OLED 모듈이 아니라 온보드 형태로 제작하고 싶은 경우가 있었습니다. 

자료를 찾기가 힘들어서 미뤄왔는데 SSD1306 드라이버를 쓰는 OLED의 경우 비교적 주변 회로가 간단한 듯 하여 도전해보게 되었습니다. 

 

 

 

 

 

 

 

요즘은 타오바오 직구를 많이 합니다.

아무래도 살 물건이 많다보니 알리보다 조금이라도 저렴해지고 직배송도 가능해서 배송도 그리 늦지 않네요.

 

 

 

 

 

셀러가 보내준 데이터를 참조해 회로를 만듭니다. 

비교적 간단하죠?

원래는 SH1106 OLED 를 구매했다가 보다 주변 회로가 간단한 물건을 찾아 SSD1306으로 변경하게 되었습니다. 

 

 

 

 

납땜을 하고 U8G2 라이브러리 예제를 올려봅니다. 

 

 

 

 

 

 

 

잘 되는군요. 

바쁘다 보니 취미 프로젝트 할 시간 내기가 힘드네요. 

 

 

728x90
728x90

아무래도 제 개인의 코딩 능력을 많이 벗어난 데이터셋 정리 등이 필요하다 보니 ChatGPT에게 도움을 청했습니다. 

한동안 이녀석과 질답을 주고받으며 코드를 많이 쌓긴 했습니다

하지만 대화가 길어지면 점점 버벅대고 결과가 산으로 가기도 하네요.

 

그래서 일단 단계별로 진행하고 코드 내용을 따로 기록하기로 합니다.

 

#include <WiFi.h>
#include <HTTPClient.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "GetLocate.h"
#include <Arduino_JSON.h>

// Wi-Fi 설정
const char* ssid = "ssid";
const char* password = "password";

const char* apiKey = "API_KEY";
const long utcOffsetInSeconds = 3600 * 9; // 한국 표준시 (UTC+9)

// 타임서버 설정
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

// 업데이트 간격 (예: 10분)
unsigned long updateInterval = 600000;
unsigned long previousMillis = 0;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  // 타임서버 연결
  timeClient.begin();
  timeClient.update();

  // 위치 정보 가져오기
  Location loc = getLocation();
  Serial.print("Location - Country: "); Serial.print(loc.country);
  Serial.print(", Region: "); Serial.print(loc.regionName);
  Serial.print(", City: "); Serial.println(loc.city);

  // 초기 날씨 정보 업데이트
  getWeatherUpdate();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= updateInterval) {
    previousMillis = currentMillis;

    // 타임서버 업데이트
    timeClient.update();

    // 현재 시간 출력
    Serial.print("Current time: ");
    Serial.println(timeClient.getFormattedTime());

    // 날씨 정보 업데이트
    getWeatherUpdate();
  }
}

// 날씨 정보를 업데이트하는 함수
void getWeatherUpdate() {
  Location loc = getLocation();
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    String weatherURL = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst";
    weatherURL += "?serviceKey=" + String(apiKey);
    weatherURL += "&numOfRows=60&pageNo=1&base_date=" + getCurrentDate();
    weatherURL += "&base_time=0630&nx=" + String(loc.nx) + "&ny=" + String(loc.ny);
    weatherURL += "&dataType=JSON"; // JSON 형식으로 요청

    http.begin(weatherURL);
    int httpCode = http.GET();

    if (httpCode > 0) {
      String payload = http.getString();
      Serial.println("Weather Data: ");
      
      // 특수문자 및 따옴표 제거 및 줄바꿈 출력
      String formattedPayload = formatPayload(payload);
      Serial.println(formattedPayload);
    } else {
      Serial.print("Error on HTTP request: ");
      Serial.println(httpCode);
    }
    http.end();
  }
}

// 날씨 API의 응답 데이터를 포맷하는 함수
// 이 함수는 JSON 응답에서 불필요한 특수문자와 따옴표를 제거하고,
// 쉼표를 기준으로 줄바꿈을 추가하여 가독성을 높인다.
String formatPayload(String payload) {
  payload.replace("{", ""); // '{' 제거
  payload.replace("}", ""); // '}' 제거
  payload.replace("[", ""); // '[' 제거
  payload.replace("]", ""); // ']' 제거
  payload.replace("(", ""); // '(' 제거
  payload.replace(")", ""); // ')' 제거
  payload.replace("\"", ""); // '"' 제거
  payload.replace(",", ",\n"); // ',' 뒤에 줄바꿈 추가
  return payload;
}

// 현재 날짜를 YYYYMMDD 형식으로 반환하는 함수
// 이 함수는 NTPClient를 사용하여 현재 시간을 가져오고,
// tm 구조체를 사용하여 로컬 시간으로 변환한 후, strftime 함수를 사용하여
// 날짜를 문자열 형식으로 반환한다.
String getCurrentDate() {
  time_t now = timeClient.getEpochTime(); // 현재 epoch 시간 가져오기
  struct tm* timeinfo = localtime(&now); // epoch 시간을 로컬 시간으로 변환
  char buffer[11]; // 날짜를 저장할 버퍼
  strftime(buffer, sizeof(buffer), "%Y%m%d", timeinfo); // 날짜를 YYYYMMDD 형식으로 포맷팅
  return String(buffer); // 문자열로 반환
}

이게 메인 코드이고요

 

 

 

#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

// Grid 구조체 정의
struct Grid {
  int x;
  int y;
};

// dfs_xy_conv 함수 선언
Grid dfs_xy_conv(const char* code, double v1, double v2);

// Location 구조체 정의
struct Location {
  String country;
  String regionName;
  String city;
  int nx;
  int ny;
};

Location getLocation() {
  HTTPClient http;
  Location loc;
  http.begin("http://ip-api.com/json");
  int httpCode = http.GET();

  if (httpCode > 0) {
    String payload = http.getString();
    JSONVar doc = JSON.parse(payload);

    if (JSON.typeof(doc) != "undefined" && strcmp((const char*)doc["status"], "success") == 0) {
      loc.country = (const char*)doc["country"];
      loc.regionName = (const char*)doc["regionName"];
      loc.city = (const char*)doc["city"];
      float lat = (double)doc["lat"];
      float lon = (double)doc["lon"];

      // 좌표를 NX, NY로 변환
      auto grid = dfs_xy_conv("toXY", lat, lon);
      loc.nx = grid.x;
      loc.ny = grid.y;
    } else {
      Serial.println("Failed to parse location data");
    }
  } else {
    Serial.println("Failed to retrieve location data");
  }
  http.end();
  return loc;
}

// dfs_xy_conv 함수 정의
Grid dfs_xy_conv(const char* code, double v1, double v2) {
  const double RE = 6371.00877;
  const double GRID = 5.0;
  const double SLAT1 = 30.0;
  const double SLAT2 = 60.0;
  const double OLON = 126.0;
  const double OLAT = 38.0;
  const double XO = 43;
  const double YO = 136;

  const double DEGRAD = M_PI / 180.0;
  const double RADDEG = 180.0 / M_PI;

  double re = RE / GRID;
  double slat1 = SLAT1 * DEGRAD;
  double slat2 = SLAT2 * DEGRAD;
  double olon = OLON * DEGRAD;
  double olat = OLAT * DEGRAD;

  double sn = tan(M_PI * 0.25 + slat2 * 0.5) / tan(M_PI * 0.25 + slat1 * 0.5);
  sn = log(cos(slat1) / cos(slat2)) / log(sn);
  double sf = tan(M_PI * 0.25 + slat1 * 0.5);
  sf = pow(sf, sn) * cos(slat1) / sn;
  double ro = tan(M_PI * 0.25 + olat * 0.5);
  ro = re * sf / pow(ro, sn);

  Grid rs = {0, 0};
  if (strcmp(code, "toXY") == 0) {
    double ra = tan(M_PI * 0.25 + (v1) * DEGRAD * 0.5);
    ra = re * sf / pow(ra, sn);
    double theta = v2 * DEGRAD - olon;
    if (theta > M_PI) theta -= 2.0 * M_PI;
    if (theta < -M_PI) theta += 2.0 * M_PI;
    theta *= sn;
    rs.x = floor(ra * sin(theta) + XO + 0.5);
    rs.y = floor(ro - ra * cos(theta) + YO + 0.5);
  }
  return rs;
}

 

이건 GetLocate.h 코드입니다.

Wifi 주소를 추적해서 현재 위치를 파악하고, 그 위치정보를 기상청 API에서 요구하는 그리드 격자정보로 변환합니다.
https://gist.github.com/fronteer-kr/14d7f779d52a21ac2f16
의 코드를 참조하도록 했습니다. 

 

 

이 코드를 실행한 결과는 다음과 같습니다.

Connecting to WiFi...
Connecting to WiFi...
Connected to WiFi
Location - Country: South Korea, Region: Gyeonggi-do, City: Seongnam-si
Weather Data: 
response:header:resultCode:00,
resultMsg:NORMAL_SERVICE,
body:dataType:JSON,
items:item:baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1000,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1000,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0700,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0800,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0900,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1000,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1100,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1200,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0700,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0800,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1100,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1200,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0700,
fcstValue:17,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0800,
fcstValue:19,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0900,
fcstValue:21,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1000,
fcstValue:23,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1100,
fcstValue:24,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1200,
fcstValue:25,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0700,
fcstValue:75,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0800,
fcstValue:70,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0900,
fcstValue:65,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1000,
fcstValue:60,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1100,
fcstValue:50,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1200,
fcstValue:45,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0700,
fcstValue:-0.8,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0800,
fcstValue:-0.4,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0.5,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1100,
fcstValue:2.2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1200,
fcstValue:2.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0.5,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0.9,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1.1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1.1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0.8,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0700,
fcstValue:118,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0800,
fcstValue:151,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0900,
fcstValue:204,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1000,
fcstValue:236,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1100,
fcstValue:250,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1200,
fcstValue:257,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0700,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0800,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1000,
fcstValue:2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1100,
fcstValue:2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1200,
fcstValue:3,
nx:62,
ny:122,
pageNo:1,
numOfRows:60,
totalCount:60

 

현재 위치정보는 성남시로 나오는데요.

핸드폰 핫스팟으로 접속했더니 현재 위치정보가 좀 많이 어긋나네요. 

이건 급한게 아니니 천천히 수정하려고 합니다. 

 

 

항목설명

baseDate 예보 발표 날짜 (YYYYMMDD 형식)
baseTime 예보 발표 시각 (HHMM 형식)
category 예보 항목 코드
fcstDate 예보 날짜 (YYYYMMDD 형식)
fcstTime 예보 시각 (HHMM 형식)
fcstValue 예보 값
nx 예보 지점의 X 좌표
ny 예보 지점의 Y 좌표

 

코드 (category)설명

LGT 낙뢰 가능성
PTY 강수 형태
RN1 1시간 강수량
SKY 하늘 상태
T1H 1시간 기온
REH 습도
UUU 동서바람성분
VVV 남북바람성분
VEC 풍향
WSD 풍속

 

 

모든 코드와 자료정리는 ChatGPT가 했습니다. 
다음은 이 데이터를 간결하게 정리해서 저장하는 부분을 추가하려고 합니다. 

728x90
728x90

*아두이노 기상청 등으로 검색이 많이 들어오는데, 잘 정리된 블로그 링크를 걸어놓겠습니다. 

관련 프로젝트를 하시는 분들은 아래 링크를 참조하세요. 

https://postpop.tistory.com/86

 

아두이노 - ESP01 모듈, 기상청 / 오픈웨더맵 API 날씨 정보 받기

아두이노에서 날씨 정보를 받기 위해서는 기상 서비스 사이트의 API KEY가 있어야 합니다. 한국의 경우 공공데이터포털, 외국 사이트는 OpenWeatherMap에서 회원가입한 뒤 KEY를 할당받아 코딩해 주어

postpop.tistory.com

 

 

 

날씨 예보를 받는 서비스는 오픈웨더맵 외에 '공공 데이터 포털'을 들 수 있습니다. 

이곳에서는 단기예보와 중기예보, 미세먼지 데이터 등 한국 상황에 훨씬 더 잘 맞는 데이터들을 얻을 수 있죠. 

https://www.data.go.kr/

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

 

 

 

 

공공데이터를 이용하려면 일단 인증키를 발급받아야 하는데요

메뉴를 조금만 찾아보시면 쉽게 인증키 신규발급 메뉴를 찾으실 수 있습니다.

발급받은 인증키는 마이페이지 메뉴에서 바로 확인 가능합니다. 

 

 

 

그리고 나서 이제 원하는 API 사용신청을 하면 됩니다. 

보통 간단한 날씨예보는 "단기예보" 를 확인하면 오늘의 시간별 날씨와 3일간의 날씨를 확인할 수 있습니다. 

[데이터찾기] - [데이터목록] 을 클릭하고 "단기예보"를 입력해 검색합니다. 

 

 

 

 

 

 

 

그리고 창을 약간 내려서 오픈API 탭을 클릭하면 "기상청_단기예보 ((구)_동네예보) 조회서비스" 가 나옵니다. 

"활용신청" 버튼을 클릭합니다. 

 

신청 메뉴에는 사용 목적 등을 간단하게 적으면 되며, 신청 즉시 사용이 가능합니다. 

 

 

 

개발용 계정은 즉시 승인되어 바로 사용할 수 있습니다.

단기예보는 하루에 10000건, 대기오염정보는 500건 제한이 있긴 한데 개인용으로 쓰기엔 전혀 문제없는 용량이죠.

 

 

 

 

 

자세한 활용방법을 알고 싶으면 조회서비스를 들어가서 하단의 .zip 파일을 다운받으면 내용을 확인할 수 있습니다. 

 

 

 

 

 

 

728x90
728x90

제가 뭐 주변지역으로 노드를 쫙 깔거나 그런 것 까지는 생각을 안했지만요. 

테스트를 하건 뭐건 적어도 주변에 고정 노드는 하나 있어야 뭔가를 하기 쉽겠더군요.

설치 위치가 고민인데 서울 도심에서 설치하는 것도 난관이고 무엇보다 자체전원을 갖춰야 한다는 것도 문제입니다.




https://austinmesh.org/#building-a-solar-powered-repeater

 

Austin Mesh

Austin Mesh is a community group working to build a mesh network of solar-powered meshtastic radios in Austin. This network acts like a city-wide text messaging system, allowing people to communicate publicly or privately with anyone on the network. All of

austinmesh.org

검색해 보니 외국의 리피터 설치 경험담이 있는데요.

텍사스 오스틴(위도 30.2672N) 에서 소형 5W 급 태양전지 등을 사용했다가 몇달만에 자꾸 노드가 죽어 몇번씩 장비를 교체한 내용들이 있습니다. 

 

이것저것 고민해보니 소형 태양광 전지를 쓰더라도 장비만 그럭저럭 가동되면 테스트는 가능할 것 같습니다. 

RAK wisblock 장비가 그나마 전력 소모가 적다고 하니 그 장비를 기준으로 할까 하는데요.

검색해 보니 이것도 태양광이 적어 전압이 불안정하면 애매하게 죽어서 복구가 안 되는 경우가 있는 듯 하더군요. 

 

그렇다면 애초에 저전압 컷 기능이 있는 태양광 충전기는 없나? 하고 또 알아보게 되었습니다.

그리고 우리의 멋진 GreatScott 형님의 과거 동영상을 보게 되었죠.
https://www.youtube.com/watch?v=kEttqWJrdww

 


내용을 몇번씩 검토해 봤는데 원하는 기능을 완벽하게 구현해 놓아 그대로 써도 될 것 같습니다.

과충전 / 과방전 / 과전류 보호에 5V 출력 부스트, MPPT까지 모두 돌아가는 충전 및 보호회로입니다.

 

 

 

 

 

다행히 회로도를 제공해 주셔서 그대로 쓰면 될 것 같지만

 

 

 

 

 

 

좀 깔끔하게 정리를 했고요. 

BOM 을 뽑아서 LCSC에 넘겨보니 재고가 없는 부품들이 있어서 대체 부품으로 다시 넣었습니다. 

 

 

 

 

 

 

 

 

 

재고없는 제품, 재고 모자란 제품 등등이 섞여서 BOM 정리하고 주문하는 게 PCB 제작보다 오래 걸렸네요

 

 

 

 

 

부품이 도착하고 납땜을 했습니다. 

일단 배터리 입력에 18650을 하나 연결하고 출력단 전압을 체크해보니 승압이 잘 되고 있습니다. 

이후 배터리 대신 파워 서플라이를 연결하고 전압을 오르락 내리락 해보니 2.5V에서 전압이 컷오프 되는 것을 볼 수 있었습니다. 

다만 다시 전압을 올리면 출력이 되지 않고 스위치를 off/on 해야 다시 출력이 나오더군요. 

만약 배터리가 위험전압까지 떨어진다면 수동으로 스위치를 껐다 켜야만 할 것 같습니다. 

 

 

 

아직 R8, R9은 납땜하지 않았는데 이는 태양전지 MPPT 전압에 맞춰야 하기 때문입니다. 
위의 GreatScott 영상에서는 9:20초쯤부터 나옵니다. 

전압분배를 이용해서 MPPT 핀에 1.205V 가 입력되도록 하면 된다는군요

 

 

태양전지의 MPPT는 잘 알지 못하므로 GPT에게 물어봤습니다. 

 

 

회로 자체는 검증된 것이라 작동에는 문제가 없을 듯 하고요.

적당한 태양전지 판을 구해서 테스트를 해 봐야 할 것 같습니다.

 

 

728x90
728x90

요즘 탐조(야생새 관찰)에 발을 들여놓을까 말까 하는 중입니다. 

원래 동물 보는건 좋아하고 새에도 관심이 많거든요. 

 

문제는 제가 극 내향형 인간에 방콕을 매우 좋아하는 사람이라는 거지요. 

주말에 방문하기로 혼자 계획을 세우고 주말이 되자 역시나 가기싫다 귀찮다 속으로 외치다가 

큰맘먹고 출발을 했습니다. 

 

 

 

 

주차하고 길을 가는데 뭐가 옆에서 후다닥 좌우로 왔다갔다 뛰네요.

사슴인지 노루인지가 울타리로 막힌 곳에서 길을 찾고 있었습니다. 

 

 

 

 

 

차를 대놓고 책방으로 향하는데 탐조하기 딱 좋은 곳이더군요.

 

 

 

 

 

뭔가 거창하게 생긴 농민회관. 

주말에는 결혼식 등 행사관계로 복잡하고 주차비도 비싸다고 하니 되도록 인근 주차를 이용하는게 좋다고 합니다. 

 

 

 

 

 

건물을 뚫고 뒤편으로 넘어가면 바로 고즈넉한 건물이 있고 간판이 보입니다. 

 

 

 

 

 

 

 

 

워크샵이나 외부 탐조행사 등이 있어 항상 오픈되어 있지 않습니다. 

그래서 네이버 블로그나 인스타그램 페이지 등에 행사관련 공지가 항상 있는데 오늘은 그런게 없었습니다.

그런데 잠겨있네요?

 

마침 시계를 보니 12시 쯤이라 식사를 하러 가셨나 하고 주변이나 둘러보려고 나왔습니다. 

쌍안경을 들고 마침 건물 외벽 배수구로 들락날락 하는 참새를 잠깐 보는데 방금 옆에 주차한 차량에서 나오신 분이

'탐조책방 오셨나요?' 하고 묻네요. 

 

타이어에 펑크가 나서 수리하느라 늦으셨다는군요. 

마침 제가 쌍안경을 들고 있어서 바로 알아채셨는데 타이밍이 잘 맞아서 다행이네요

 

 

 

 

 

 

 

아기자기한 내부와 귀여운 소품들.

목적이던 조류도감류와 함께 몇권의 책을 구매하고 재미있는 설명을 듣고 나왔습니다. 

사장님이 참 친절하시고 부담스럽지 않게 설명도 잘 해주셔서 먼 거리를 왔던 보람이 있네요

 

 

 

 

 

이곳은 새들 때문에 일부러 심었는지 사방에 오디나무가 가로수마냥 있어 땅바닥에도 많이 떨어져 있습니다. 

어르신 두분이 열심히 줍고 있네요. 

보통 저런거 보면 좀 눈쌀이 찌푸려 질 때도 있는데

여긴 워낙 많으니 땅에 떨어져 밟히고 썩는 것보다 차라리 나아 보일 정도입니다. 

 

 

 

 

 

 

 

구매한 책을 차에 두고 호수를 한바퀴 돌아보기로 합니다. 

 

 

 

 

 

 

 

 

핸드폰 카메라로 찍은 왜가리 

 

 

 

 

 

쌍안경으로 보니 순 국내산 민물장어를 잡아먹고 있던 왜가리.

맛있겠다...

 

 

 

 

 

 

 

 

여긴 가마우지들이 바글바글 합니다. 

깃털의 방수력이 좋지 않다고 하는데, 물에 떠있을 때도 다른 물새들과 달리 몸통이 거의 잠겨있더군요. 

눈앞에서 잠수하는 걸 봤는데 각기 다른 녀석들이 한놈은 나뭇가지를 물고 올라오고 한놈은 잎사귀를 물고 올라오고.. 

제게 이녀석의 이미지는 약간 맹탕으로 굳어지고 있습니다. 

 

 

 

 

 

 

 

호수를 한바퀴 돌아보니 이런것도 있는데, 배율이 높긴 하지만 관리가 잘 안되어 살짝 뿌옇고 별로네요

그냥 쌍안경 보는게 나았습니다. 

 

 

 

 

 

 

집에 와서 오늘 구매한 책으로 동정.

처음 본게 대백로인듯 하군요. 다리가 살짝 노랬습니다. 

 

 

 

 

 

오리는 청둥오리 암컷인가 했는데 흰뺨검둥오리네요. 

옆에서 봤을 때 흰 줄무늬가 두줄. 부리 끝이 노란색. 

 

 

탐조활동이 나름 재미있긴 하지만 실외활동을 극히 싫어하는지라 과연 앞으로 어떻게 될지?

더위에 약해 일단 여름이 오면 정말 아무것도 못할듯 하고 좀 시간이 지나봐야 할 듯 합니다. 

728x90
728x90

Openweathermap에서 날씨를 받아와 사용하려 했는데 데이터 변환 과정에서 골치아픈 부분이 있었습니다. 

차후 4.2" 전자잉크 등 보다 화면이 넓은 기기를 사용하기 위해서 당일의 온도변화, 7일치의 날씨변화 등도 있었으면 했고요.

무엇보다 현재 날씨는 알 수 있는데 당일 날씨나 최저, 최고 온도 등 우리가 흔히 쓰는 기준으로 데이터를 얻기가 힘들더군요.

 

 

그리고 이 모든 것을 ChatGPT4.0 에게 맡겼습니다. 

 

 

 

 

 

 

 

 

저는 그냥 이렇게 해줘, 저렇게 해줘, 여기 틀렸잖아

를 반복하다 보니 코드는 손도 안대고 좋은 결과가 나오더군요

 

 

금일 온도 / 최저 / 최고온도 / 체감온도/ 구름 / 풍속 / 강수량 / 강설량 등이 잘 정리되어 출력된 것을 볼 수 있습니다. 

5일간 날씨 데이터도 마찬가지로 정리되어 나오고 있고요

 

 

 

아래는 이 코드입니다.

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

// WiFi 설정
const char* ssid = "Yourssid";
const char* password = "yourPW";

// OpenWeatherMap API 키
String openWeatherMapApiKey = "YourAPI";

// 서울의 도시명과 국가 코드
String city = "Seoul";
String countryCode = "KR";

// 업데이트 주기 설정 (15초)
unsigned long lastTime = 0;
unsigned long timerDelay = 15000; 

void setup() {
  Serial.begin(115200); // 시리얼 모니터 시작
  Serial.println("serial start"); // 디버깅 메시지 추가
  WiFi.begin(ssid, password); // WiFi 연결 시작
  Serial.println("Connecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // 즉시 첫 번째 API 호출을 위해 lastTime 초기화
  lastTime = millis() - timerDelay;
}

void loop() {
  // 타이머가 만료되었을 때 데이터 요청
  if ((millis() - lastTime) > timerDelay) {
    if (WiFi.status() == WL_CONNECTED) {
      // API 요청 URL 구성 - 3시간 간격의 5일 예보 데이터
      String serverPath = "https://api.openweathermap.org/data/2.5/forecast?q=" + city + "," + countryCode + "&appid=" + openWeatherMapApiKey + "&units=metric";
      
      // 데이터 요청 및 수신
      String weatherData = httpGETRequest(serverPath.c_str());
      if (weatherData != "{}") { 
        parseWeatherData(weatherData); // 수신된 데이터 파싱
      }
      lastTime = millis();
    } else {
      Serial.println("WiFi Disconnected");
    }
  }
}

// HTTP GET 요청 함수
String httpGETRequest(const char* serverName) {
  WiFiClientSecure client; 
  client.setInsecure();    // SSL 인증서 검증 무시
  HTTPClient http;
  http.begin(client, serverName); // HTTPS 연결 시작
  Serial.println("Requesting URL: " + String(serverName));

  int httpResponseCode = http.GET();
  
  String payload = "{}";
  if (httpResponseCode == 200) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  } else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
    payload = http.getString(); 
    Serial.println("Error response: " + payload);
  }
  http.end();
  return payload;
}

// 타임스탬프를 한국 표준시(KST)로 변환하는 함수
String convertUnixTimeToKST(long unixTime) {
  unixTime += 9 * 3600; // UTC+9 시간대 보정
  time_t t = unixTime;
  struct tm *tmStruct = localtime(&t);
  char buffer[30];
  strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tmStruct);
  return String(buffer);
}

// 날씨 데이터 파싱 함수
void parseWeatherData(String json) {
  JSONVar myObject = JSON.parse(json);
  if (JSON.typeof(myObject) == "undefined") {
    Serial.println("Parsing failed!");
    return;
  }

  // 오늘 날씨 데이터 파싱 및 출력
  Serial.println("Today's Weather Data:");
  JSONVar list = myObject["list"];

  // 하루 동안의 데이터에서 최저/최고 온도 계산
  float dayMinTemp = 1000;
  float dayMaxTemp = -1000;
  for (int i = 0; i < 8; i++) { // 24시간 내의 3시간 간격 데이터
    JSONVar data = list[i];
    float temp_min = (float)(double)data["main"]["temp_min"];
    float temp_max = (float)(double)data["main"]["temp_max"];
    if (temp_min < dayMinTemp) dayMinTemp = temp_min;
    if (temp_max > dayMaxTemp) dayMaxTemp = temp_max;
  }
  JSONVar todayData = list[0];
  float temp = (float)(double)todayData["main"]["temp"];
  float feels_like = (float)(double)todayData["main"]["feels_like"];
  const char* weather_description = (const char*)(todayData["weather"][0]["description"]);
  float humidity = (float)(double)todayData["main"]["humidity"];
  float clouds = (float)(double)todayData["clouds"]["all"];
  float wind_speed = (float)(double)todayData["wind"]["speed"];
  float rain = todayData.hasOwnProperty("rain") ? (float)(double)todayData["rain"]["3h"] : 0;
  float snow = todayData.hasOwnProperty("snow") ? (float)(double)todayData["snow"]["3h"] : 0;

  Serial.print("Temp: ");
  Serial.println(temp);
  Serial.print("Min Temp: ");
  Serial.println(dayMinTemp);
  Serial.print("Max Temp: ");
  Serial.println(dayMaxTemp);
  Serial.print("Feels Like: ");
  Serial.println(feels_like);
  Serial.print("Humidity: ");
  Serial.println(humidity);
  Serial.print("Clouds: ");
  Serial.println(clouds);
  Serial.print("Weather: ");
  Serial.println(weather_description);
  Serial.print("Wind Speed: ");
  Serial.println(wind_speed);
  Serial.print("Rain Volume (3h): ");
  Serial.println(rain);
  Serial.print("Snow Volume (3h): ");
  Serial.println(snow);
  Serial.println("-------");

  // 5일간 날씨 데이터 파싱 및 출력
  Serial.println("5 Days Weather Data:");
  for (int day = 0; day < 5; day++) {
    float minTemp = 1000;
    float maxTemp = -1000;
    float avgHumidity = 0;
    float avgClouds = 0;
    float avgWindSpeed = 0;
    float totalRain = 0;
    float totalSnow = 0;
    int count = 0;
    String weatherDescriptions = "";

    for (int i = day * 8; i < (day + 1) * 8 && i < list.length(); i++) {
      JSONVar dayData = list[i];
      float temp_min = (float)(double)dayData["main"]["temp_min"];
      float temp_max = (float)(double)dayData["main"]["temp_max"];
      float humidity = (float)(double)dayData["main"]["humidity"];
      float clouds = (float)(double)dayData["clouds"]["all"];
      float wind_speed = (float)(double)dayData["wind"]["speed"];
      float rain = dayData.hasOwnProperty("rain") ? (float)(double)dayData["rain"]["3h"] : 0;
      float snow = dayData.hasOwnProperty("snow") ? (float)(double)dayData["snow"]["3h"] : 0;
      const char* weather_description = (const char*)(dayData["weather"][0]["description"]);

      if (temp_min < minTemp) minTemp = temp_min;
      if (temp_max > maxTemp) maxTemp = temp_max;
      avgHumidity += humidity;
      avgClouds += clouds;
      avgWindSpeed += wind_speed;
      totalRain += rain;
      totalSnow += snow;
      weatherDescriptions = String(weather_description);
      count++;
    }
    avgHumidity /= count;
    avgClouds /= count;
    avgWindSpeed /= count;

    long date = (long)list[day * 8]["dt"];
    Serial.print("Date: ");
    Serial.print(convertUnixTimeToKST(date));
    Serial.print(", Min Temp: ");
    Serial.print(minTemp);
    Serial.print(", Max Temp: ");
    Serial.print(maxTemp);
    Serial.print(", Humidity: ");
    Serial.print(avgHumidity);
    Serial.print(", Clouds: ");
    Serial.print(avgClouds);
    Serial.print(", Wind Speed: ");
    Serial.print(avgWindSpeed);
    Serial.print(", Rain Volume (3h): ");
    Serial.print(totalRain);
    Serial.print(", Snow Volume (3h): ");
    Serial.print(totalSnow);
    Serial.print(", Weather: ");
    Serial.println(weatherDescriptions);
    Serial.println("-------");
  }
}

 

 

그렇지만 이 모든 걸 갈아엎게 되는데.. 다음 포스팅에 이어서 쓰겠습니다.

728x90

+ Recent posts