2019 May IoT project

As I previously posted, I made a WiFi AC remote controller project. see telegram bot for HVAC

Today, I begin a new project to go further.

I purchased another Raspberry Pi 3 Model B, AND Raspberry Pi Sensor Kit. (http://m.eleparts.co.kr/goods/view?no=3730500 and http://m.eleparts.co.kr/goods/view?no=3030452)

(I just wanted to purchase sensor only, but I can’t sure, I could attach these sensors to my existing RPi, so I posted a question to a forum https://www.cooking-hacks.com/forum/viewtopic.php?f=43&t=19434&sid=d89e064868d4a0dce0c58ea7a6490bde)

And, I tested DHT11 as https://github.com/deokgonkim/rpi_sensor

 

My next step will be,

1. set up a messaging queue, like Rabbit MQ

2. set up a web/api server for gathering the data and the controll center.

3. my existing bot code shoud be migrated to a new server, and these two RPi should listen to MQ for commands, and should send data to MQ.

 

To be continued…

Continue reading 2019 May IoT project

2018년 기록

1. Python Tkinter Desktop App
2. Raspberry pi HVAC Wifi Remote, Telegram chatbot
3. 9월 : 쌀밥 -> 고기야채로 전환 (저녁만 해당, 아침은 라면(밥->라면으로 복귀))
4. Hulk server reborn -> 빈 서버로 몇 달간 방치되어 있다가, 일반적인 개발 서버로 용도 전환. (메모리도 32GB로 확장)
5. 10월 iPhone 7으로 바꿈. (iPhone 6S 3년)
6. iOS 앱 개발 준비중(Objective-C) : 여전히 앱스토어에는 올리지 못하고, 연습만 계속 중.

Python 개발 기록
– 3월 : 에이전트 형태의 데몬 개발. 분산된 서버(에이전트)의 운용 상황을 중앙서버로 전송하는 역할
Python, log parsing(no library, not re), cx_Oracle, Periodic Data Collection, Windows WMI and CMD, Sqlite3
– 9월 : 위 에이전트에서 수집한 정보를 편하게 보는 프로그램 개발
Python, Tkinter, cx_Oracle, Chat(udp broadcasting), Socket Proxy, RDP Proxy, encryption with 3rd party software
– 12월 : 데이터 연계를 위한 XMLRPC 데몬
Python, SimpleXMLRPCServer, argparser

지른 것.
– iPhone 7 (10월)
– iPhone 7용 지갑형 케이스 (카드 3장 휴대하여, 지갑을 휴대하지 않을 수 있게 되었다.)
– iPhone용 Lightning Digital AV 어댑터 : HDMI 디스플레이에 iPhone 화면을 띄울 수 있다.

– Youtube Premium : 더 이상 광고를 보지 않고, 동영상을 볼 수 있다.

– IR Transceiver for aduino : 에어컨, TV를 Raspberry pi를 통해 원격 제어하는 것을 만들었지.

trivial
– FANN 시작만 하다가 접음.
– tensorflow 시작만 하다가 접음.
– Libreboot X200 Linux – Trisquel 업그레이드(7.0 -> 8.0), 96DPI -> 125DPI로 변경. DPI변경이 이렇게 보기 좋은 것이구나(?)
– sharedrop
– pgp everywhere, GPG, Yubikey SMIME
– openvpn notification https://www.gargoyle-router.com/phpbb/viewtopic.php?t=5756

telegram bot 제 2탄

텔레그램 봇을 만들어 보았었지요.

이번엔 그 두 번째 이야기.

HVAC IR Remote라는 라즈베리파이에 올릴 수 있는 IR Transceiver를 구매하고,
원격에서 집에 있는 장치를 리모콘 조작하듯이 켜고 끌 수 있는 것을 만들어 보았습니다.

Github : https://github.com/deokgonkim/lirc-telegram-bot


# hvac-telegram-bot

## My Hardware

* Raspberry Pi Model B. (old one)
* HVAC IR Remote for arduino / Raspberry Pi
* https://www.cooking-hacks.com/hvac-ir-remote-shield-for-raspberry-pi
* https://www.cooking-hacks.com/documentation/tutorials/control-hvac-infrared-devices-from-the-internet-with-ir-remote/

## Setting up HVAC IR Remote for LIRC

* Instructions

> https://www.hackster.io/austin-stanton/creating-a-raspberry-pi-universal-remote-with-lirc-2fd581

* Install lirc package

```
sudo apt-get install lirc
```

* Configure kernel module

```
vi /etc/modules
lirc_dev
lirc_rpi gpio_in_pin=18 gpio_out_pin=23
```
> note I/O port is different than above documentation.
> You can find GPIO port for HVAC IR Remote in arduPi.cpp

```
vi /etc/lirc/hardware.conf
```
> see above document

```
vi /etc/lirc/lirc_options.conf
```
> https://raspberrypi.stackexchange.com/questions/50873/lirc-wont-transmit-irsend-hardware-does-not-support-sending
> set driver to 'default'

* Record IR signal or obtain configuration file.
> http://lirc.sourceforge.net/remotes/

> My testing board didn't work as expected.
> I can only control IR LED, two buttons, two indication LEDs. but can't read IR signal. I don't know board is broken or something.

## Preparations

following my own blog https://www.dgkim.net/wordpress/2017/08/24/telegram-bot-%ed%85%8c%ec%8a%a4%ed%8a%b8-%eb%85%b8%ed%8a%b8/

### python-telegram-bot
> I tried
```
git clone https://github.com/python-telegram-bot/python-telegram-bot

cd python-telegram-bot
git submodule update
```

> But, today I changed plan.
> https://pypi.org/project/python-telegram-bot/

## programming part

> I referenced https://github.com/python-telegram-bot/python-telegram-bot/tree/master/examples

> quickly created firstbot.py

Big-O notation

(S3 * N^3) + (S2 * N^2) + (S1 * N) + S0

중첩된 루프 구조를 가질 때, 문장의 수행 횟수를 구하는 위 공식에서,
S0은 가장 루프 바깥의 문장이며,
S1은 1단계 루프 내의 문장
S2는 2단계 루프 내의 문장
S3은 3단계 루프 내의 문장
N은 반복 횟수를 의미 합니다.

그래서, Big-O 표기법으로, 위의 문장은 O(N^3)로 표기할 수 있습니다?

C/S 과정을 정식으로 배운 것이 아니라, 오늘 책에서 본 내용을 간략히 정리해 봅니다.

telegram bot 테스트 노트

얼마전, telegram 공개 채널을 한번 만들어 보았다.

https://t.me/okkykr

그리고, bot을 다시 한번 테스트 해볼까 시동을 걸었다.

시작은.. 검색 ‘telegram python bot’

https://github.com/python-telegram-bot/python-telegram-bot

git clone 받고, git submodule update 하고, …

… 두둥 …


ImportError: No module named future.backports.urllib

음, … pip install을 피하고자 했는데, …
음, … future란 것도 모듈이네, 이런 건 설치해보자.

https://pypi.python.org/pypi/future/0.16.0
다운로드 받고, setup.py install 사용해서 설치함.

다시한번


>>> import telegram
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "telegram/__init__.py", line 94, in <module>
from .bot import Bot
File "telegram/bot.py", line 34, in <module>
from telegram.utils.request import Request
File "telegram/utils/request.py", line 31, in <module>
import certifi
ImportError: No module named certifi

… 두둥 …

certifi란 것도 필요하구나.
https://pypi.python.org/pypi/certifi/2017.7.27.1
그런데, … .whl 음.. 느낌이 안 좋다.

pip를 설치하자.
https://stackoverflow.com/questions/17271319/how-do-i-install-pip-on-macos-or-os-x

다음. pip install certifi

다시한번


>>> import telegram
>>>

되는 것 같다.

… 잠시 추가로 테스트 …
( bot을 만드는 것도, telegram은 웹 관리자 화면 같은 걸 통하지 않고 봇에게 말을 걸어서 만든다. … 만들었다. )

… 1분 후, …


>>> import telegram
>>> bot = telegram.Bot(token='nnnnnn:alphanumber')
>>> bot.get_me()
<telegram.user.User object at 0x10x10x10x>
>>>

된다.

… 10분 후, …
봇에게 말을 걸어보고, 봇이 응답하게 해보았다.


>>> updates = bot.get_updates()
>>> updates
[]
>>> updates = bot.get_updates()
>>> updates
[<telegram.update.Update object at 0x10x10x10x>, <telegram.update.Update object at 0x10x10x10x>]
>>> chat_id = bot.get_updates()[-1].message.chat_id
>>> chat_id
1x60x39x2
>>> bot.send_message(chat_id=chat_id, text="I'm a bot")
<telegram.message.Message object at 0x10x10x10x>

다음 단계, bot 을 채널에 초대해보자.

https://stackoverflow.com/questions/42674340/how-to-join-my-telegram-bot-to-public-channel
https://stackoverflow.com/questions/33126743/how-do-i-join-my-bot-to-the-channel

관리자가 관리자로 추가할 수 있군.

… 8분 후, …


>>> bot.send_message(chat_id='@dgkimnet', text='hi')
<telegram.message.Message object at 0x10x10x10x>

올, 된다. 지금 만든 것은, 말하기 전용? 이지만. 되긴 된다. 듣고 반응하는 것도 가능하겠지만. 지금 하기에는 dgkim이 너무 나태하다.

ps. 워드프레스에서 코드 활용할 때, lt, gt 넣는 것 참 번거롭네.

북마크 프로그램 만들려 하면서, …

일전 포스트에서 적었듯, SiteBar( http://sitebar.org/ ) 대신할 프로그램을 만들어볼까 고민중인데, …

기술적인 구현도 문제지만 ( RESTful Server, 인증 )

개념적인 구현도, 막상 닥쳐보니 고민할 것이 많다.

우선, Tag 개념은 넣을려고 하는데, 이건 그리 복잡하지 않을 수 있겠다 싶기도 한데, …
( 실제 데이터 모델을 생각하니 복잡할 수도. … )

먼저, Category 혹은 Directory 개념은 있어야 할 듯 하고, 바로 막막하네, …
그래서, 잠시 ownCloud 같은 클라우드를 백으로 활용할까 생각하고, …

Directory 개념은 Tree 구조로 가져가는 것이 복잡할 것 같지만, 향후를 생각해도 기본적인 것 같아 복잡하다.

추가로, … public, private 개념을 두려고 하니, … 또 하나, ACL 넣기가 필요하다.

역시나 기존에 구현된 filesystem의 권한 및 tree 구조를 바로 활용하면 편한데, …
이번 프로젝트는 직접 구현해 보는 것이 목표라서 re-inventing wheel은 하려고 한다.

firefox의 bookmark API는 우선 고려 대상에서 제외하고, ( bookmark를 사용할 분들은 잘 사용하시고, 나는 따로 서버에 두고, bookmark와는 별개의 sidebar와 web interface, 앱 인터페이스로 가려고 한다 … )

그래서 생각하는 것이, sidebar를 사용하고, 거기에 SiteBar와 유사하게 디렉토리 구조를 표현하면서, drag and drop을 편하게 해 보고자 한다.

drag and drop은 내 블로그에 전에 테스트하던 것을 참조하면서도, 오늘 추가로 아래 자료도 보고,
https://developer.mozilla.org/en-US/docs/Web/Events/drop
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations
https://24ways.org/examples/marking-up-a-tag-cloud/example.html

게시판도 하나 직접 만들어보지 않은 dgkim이라, directory, acl, tag, 인증을 적절하게 만들어보면, 다른 업무용 프로그램 만드는데도 쉽게 재활용할 수 있지 않을까 기대하는데, …
기존 구현된 tree나 relation, rdb 구조를 보면 어렵지는 않을 것 같은데, 로직 코드를 그다지 꺼내쓰듯 하지 못하니 어려움으로 다가오는듯 하다.

ps. 그리고, 만들고 나서는 현재의 2900여개의 북마크를 이전해야 하는데, …
여전히, 내 자료 저장은 좀 다양한 도구에 의존하는데, 개선해야 하나 싶기도 하고, … 메일, 블로그, 클라우드, 파일서버, 북마크, 노트, …

그러고 보니, 북마크를 만들고 나면, 자신감을 가지고 노트도 대신할 것을 만들까 싶지만, 거기에는 문서 표현(wiki? or html?)이라는 어려운 벽이 또 하나 있다.

firefox sidebar를 준비해보다…

아래 삽질 기록이 좀 있습니다만.

우선, 기본적인 클라이언트측 컨셉은 가능하겠다는 판단까지 왔습니다.

우선, webextension 예제에서 2가지를 테스트하였고, 조합하면 동작할 것 같습니다.

https://github.com/mdn/webextensions-examples/tree/master/annotate-page
위 예제를 통해서, sidebar를 띄우는 방법이 나왔습니다.
단, sidebar 내용이 서버측 내용이 아닌 로컬 내용인데, 로컬에서 커버할지 웹을 띄울지 고민이 필요한 것 같습니다.

https://github.com/mdn/webextensions-examples/tree/master/bookmark-it
bookmark에 바로 접근하는 것이 가능한 것으로 나오는데,
이걸 활용하고, 로컬 북마크와 서버측 북마크를 연동할 것인지는 고민이 필요합니다.

annotate-page는 sidebar에 뭔가 표시가 가능하다는 것을 의미하며,
bookmark-it은 currentTab.url에 접근 가능하고, XHR 요청이 가능하다는? 것이 테스트되었습니다.

이제 이걸 쓸만하도록 클라이언트 앱을 만드는 것이 필요한데, …
먼저 해결해야할 산이 남은 것이 아래 적은 것과 같이. codeigniter restful 서버 만드는 것, 그 전에 인증 문제 해결하는 것 등이 남았네요. 웹에 표현하는 tag cloud 같은 건 논외로 하더라도, …

어쨌든, firefox extension 완성되면, codeigniter 버전도 만들어 보고, django 버전도 만들어 보면 좋겠다는 계획입니다. … 이 계획이 언제 실현되어 제품으로 나올지는 모르겠지만 … spring에서는 restful API나, spring-security가 경험이 있어 model만 만들면 바로 동작하는 것은 만들 수 있겠다고 생각하지만,, …. 무엇보다 큰 문제는, 사용자 웹 인터페이스가 …


예전에는 SiteBar라는 프로그램을 사용하여 북마크를 관리?했었습니다.

그러던 중, SiteBar가 PHP7과 호환성 문제가 있어 사용하지 못하게 되었습니다.

그래서 이번에는 한번 만들어 볼까? 고민하고 있었지요.

간편한 시작을 위해서 웹서버쪽을 PHP + CodeIgniter사용하고,
클라이언트는 Firefox Sidebar를 사용해 보고자 했습니다.

Firefox Sidebar를 만드는 방법이 역사가 있고, 바뀌어 가기도 하는데, 그중 최신인,
web extension을 사용해서 틀을 잡아보기로 하였습니다.

https://github.com/mdn/webextensions-examples/

그런데, …

XHR을 통해서 링크를 서버로 보내는 것을 준비하다가, …

심각한 상황에 빠졌느데, … CI에서 log_message 걸다보니, httpd가 hang 걸리고, …

그러다가, gdb, lsof, debuginfo-install httpd-2.4.6-45.el7.centos.x86_64
하는 상황까지 오게된. …

그나 저나, 해야 할 일들은 아래와 같이 시작도 못했는데, …

1. firefox web extension 사용하여 sidebar 활용 등의 클라이언트 프로그램 준비
2. 서버측 bookmark 모델 설계
3. 서버측 codeigniter LDAP 및 인증 모듈 개발
4. 서버측 codeigniter bookmark RESTful 인터페이스 개발
5. 서버측 codeigniter web 인터페이스 개발 ( bootstrap 사용할까? )

참조 URL
https://developer.mozilla.org/en-US/docs/Mozilla/Creating_a_Firefox_sidebar
https://github.com/kyoshino/simple-sidebar
https://developer.mozilla.org/en-US/Add-ons/WebExtensions
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/user_interface/Sidebars
https://github.com/mdn/webextensions-examples/

ps. 헐, 위에 적은 debuginfo-install은 시작이었고, 아래와 같은 엄청난 메시지가 나오는데, 포기할까 싶은 생각이 바로 …
debuginfo-install bzip2-libs-1.0.6-13.el7.x86_64 cyrus-sasl-lib-2.1.26-20.el7_2.x86_64 elfutils-libelf-0.166-2.el7.x86_64 elfutils-libs-0.166-2.el7.x86_64 file-libs-5.11-33.el7.x86_64 freetype-2.4.11-12.el7.x86_64 gmp-6.0.0-12.el7_1.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.14.1-27.el7_3.x86_64 libX11-1.6.3-3.el7.x86_64 libXau-1.0.8-2.1.el7.x86_64 libXpm-3.5.11-3.el7.x86_64 libattr-2.4.46-12.el7.x86_64 libcap-2.22-8.el7.x86_64 libcom_err-1.42.9-9.el7.x86_64 libcurl-7.29.0-35.el7.centos.x86_64 libgcc-4.8.5-11.el7.x86_64 libgcrypt-1.5.3-13.el7_3.1.x86_64 libgpg-error-1.12-3.el7.x86_64 libidn-1.28-4.el7.x86_64 libjpeg-turbo-1.2.90-5.el7.x86_64 libpng-1.5.13-7.el7_2.x86_64 libssh2-1.4.3-10.el7_2.1.x86_64 libstdc++-4.8.5-11.el7.x86_64 libuuid-2.23.2-33.el7.x86_64 libxcb-1.11-4.el7.x86_64 libxml2-2.9.1-6.el7_2.3.x86_64 libxslt-1.1.28-5.el7.x86_64 libzip-0.10.1-8.el7.x86_64 mariadb-libs-5.5.52-1.el7.x86_64 mod_dav_svn-1.7.14-10.el7.x86_64 mod_wsgi-3.4-12.el7_0.x86_64 nspr-4.11.0-1.el7_2.x86_64 nss-3.21.3-2.el7_3.x86_64 nss-softokn-freebl-3.16.2.3-14.4.el7.x86_64 nss-util-3.21.3-1.1.el7_3.x86_64 openldap-2.4.40-13.el7.x86_64 openssl-libs-1.0.1e-60.el7.x86_64 php-5.4.16-42.el7.x86_64 php-common-5.4.16-42.el7.x86_64 php-gd-5.4.16-42.el7.x86_64 php-ldap-5.4.16-42.el7.x86_64 php-mbstring-5.4.16-42.el7.x86_64 php-mysql-5.4.16-42.el7.x86_64 php-pdo-5.4.16-42.el7.x86_64 php-process-5.4.16-42.el7.x86_64 php-xml-5.4.16-42.el7.x86_64 python-libs-2.7.5-48.el7.x86_64 sqlite-3.7.17-8.el7.x86_64 subversion-libs-1.7.14-10.el7.x86_64 t1lib-5.1.2-14.el7.x86_64 xz-libs-5.2.2-1.el7.x86_64
지금 서버가 테스트 개발 서버라면 몰라도, 준 운용 서버인데, 위와 같은 짓을 하기는 싫은데, …

ps. 환장할 일일쎼… Java는 보통 hang상황에서 thread dump라는 편리한 도구를 사용했었고, apache는 server-status 활용하고, tcpdump나 lsof 등으로 대충 찍으면, 뭔짓을 하는지 나왔었는데, … 지금 버그인지, 뭔지는, gdb로 찾아야 하다니 하면서, …

ps. 정확한 원인은 모르겠으나, 우선 보이는 것부터 잡아보려고, …
#9 0x00007f01cba6a344 in php_verror (docref=, params=params@entry=0x7f01cbb81ce5 “”, type=type@entry=2,
format=format@entry=0x7f01cbb7bb08 “It is not safe to rely on the system’s timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you”…,
args=args@entry=0x7fff62819750) at /usr/src/debug/php-5.4.16/main/main.c:862

오늘은 가볍게, vuejs 시작해보기. … 그러다가, bootstrap으로 …

어제, vuejs, reactjs, angularjs 관련 글을 보고, …

angular 같은 경우, typescript 압박에 … 시작하다 말았고, … react도 나중에 보기로 하면서, …

그나마 가볍게 시작하기 좋지 않을까 생각에 vuejs를 시작해 본다. … test 서버를 빨리 만들면 좋은데, 돈이 없어서, …

시작 글을 적어 두고, 차근 차근 시작 …

{{ }} 구문으로 데이터를 전달하는 것이 쉽게 이해되긴하는데, …
v-bind 까지도 쉬운데, … v-if v-for 넘어가니 뭔가 새로운 세상이 열리는 듯 하다. …
일부러 오류를 일으켜 보아야지…
구문 오류나 이름 오류도 잘 잡아내긴 하네, … 역시나 스크립트 영역이다 보니, 이런 특징 때문에 싫어할 사람도 있을 듯.

component까지 오니, 다른 느낌이 있다.
jquery 같은 경우, DOM은 그대로 두고, 거기에 붙여서 쓸 수 있게 해 뒀다고 한다면,
vuejs 같은 경우, DOM에 대한 통제를 완전히 가져가 버린 듯.

참 좋은데, 개념도 알겠고, 코드와 뷰를 엮어 준다는 것까지는 알겠는데, …
extjs 같은 실제 화면 디자인을 품고 있는 것은 아닌 듯 하다,
dgkim은 바로 제품으로(?) 쓸 수 있는 디자인 및 CSS가 포함된 것이 필요한데, …

bootstrap을 파 보아야 할까?

그래서, 바로 bootstrap으로 전환하여 이어 나가본다.

bootstrap 시작하고, navigation bar 따라해 보았다. …

그런데, .. 머리속에 아직 만들고 싶은 것의 스케치가 없어서 이어나가지 못한다.

NodeJS, MongoDB 볼까?

javascript가 참 끌리는 언어이다.

nodejs의 한계도 있는데…

MongoDB document db 개발자에게 유리한 것은 많은데, ….

성능이 문제가 안 될까 싶은데, 아래 인용구가 답

The RDBMS optimizes data for storage efficiency (as it was conceived at a time when storage was the most expensive component of the system).

MongoDB’s document model is optimized for how the application accesses data (as developer time and speed to market are now more expensive than storage).

조직도 JavaScript 실험. recursive function. 연습.

커뮤니티에 javascript를 사용하여, 조직도를 구현하는 것에 대한 질문이 올라왔다.
그래서, 나는 프로그래밍 연습을 하기 위해서, 한 번 만들어보기로 결심하고, 답변을 올렸다.

https://okky.kr/article/389606

올리자마자 다시 봐도, 코드 상에 잘못된 부분은 보이지만, 그런 것들은 나중에 시간날지 고칠지 하고, 우선 코드를 내 블로그에 복사해 놓는다.

var depth1 = [];
var depth2 = [];
var depth3 = [];
var depth4 = [];

depth1.push(
    {
        GROUP_ID: 1,
        GROUPNAME: '본사',
	children: []
    },
    {
        GROUP_ID: 2,
        GROUPNAME: '지사',
	children: []
    }
);

depth2.push(
    {
        GROUP_ID: 10,
        GROUP_ID_P: 1,
        GROUPNAME: '기술지원본부',
	children: []
    },
    {
        GROUP_ID: 20,
        GROUP_ID_P: 1,
        GROUPNAME: '연구소',
	children: []
    },
    {
        GROUP_ID: 30,
        GROUP_ID_P: 2,
        GROUPNAME: '영업부',
	children: []
    }
);

console.log(depth1);
console.log("========================================");
console.log(depth2);
console.log("========================================");

/*
var datasource = { children: [] };

for(var i=0; i < depth1.length; i++){
	datasource['children'].push({'name': depth1[i]['GROUPNAME'], 'gid': depth1[i]['GROUP_ID'],'children': []});
	for(var j=0; j < depth2.length; j++){
		if(depth1[i]['GROUP_ID'] == depth2[j]['GROUP_ID_P']){
			datasource['children'][i]['children'].push({'name': depth2[j]['GROUPNAME'], 'gid': depth2[j]['GROUP_ID'], 'children':[]});
			for(var k=0; k < depth3.length; k++){
				if(depth2[j]['GROUP_ID'] == depth3[k]['GROUP_ID_P']){
					for(var l=0; l < datasource['children'][i]['children'].length; l++){
						if(depth2[j]['GROUP_ID'] == datasource['children'][i]['children'][l]['gid']){
							datasource['children'][i]['children'][l]['children'].push({'name': depth3[k]['GROUPNAME'], 'gid': depth3[k]['GROUP_ID'], 'children':[]});
							for(var m=0; m < depth4.length; m++){
								if(depth3[k]['GROUP_ID'] == depth4[m]['GROUP_ID_P']){
									for(var n=0; n < datasource['children'][i]['children'][l]['children'].length; n++){
										if(depth3[k]['GROUP_ID'] == datasource['children'][i]['children'][l]['children'][n]['gid']){
											datasource['children'][i]['children'][l]['children'][n]['children'].push({'name': depth4[m]['GROUPNAME'], 'gid': depth4[m]['GROUP_ID'], 'children':[]});
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

console.log("===== FINAL =====");
console.log(JSON.stringify(datasource));
*/

/**
 * tree에서 gid를 가지는 객체를 반환한다.
 * 못 찾으면 undefined를 반환한다.
 */
function findById(tree, gid) {

	//console.log("========================================");
	//console.log(new Error().stack);
	//console.log("========================================");

	if ( tree['GROUP_ID'] == gid ) {
		return tree;
	} else if ( tree.children.length == 0 ) {
		return undefined;
	} else {
		for ( var i = 0 ; i < tree.children.length ; i ++ ) {
			var found = findById(tree.children[i], gid);
			if ( found !== undefined ) {
				return found;
			}
		}
		return undefined;
	}
}

var ROOT = {
	'GROUP_ID': 0,
	'GROUPNAME': 'ROOT',
	'children': []
}

depth1 = depth1.concat(depth2);
for ( var i = 0 ; i < depth1.length ; i ++ ) {
	if ( depth1[i]['GROUP_ID_P'] === undefined ) {
		ROOT.children.push(depth1[i]);
	} else {
		var parent = findById(ROOT, depth1[i]['GROUP_ID_P']);
		if ( parent !== undefined ) {
			parent.children.push(depth1[i]);
		}
	}
}

console.log("FINAL");

console.log(JSON.stringify(ROOT));