하이브리드 앱 개발(Win32)

Cordova와 안드로이드 스튜디오를 이용하여 개발할때의 환경이다.
1. 프로젝트 생성

C:\CordovaBuild>cordova create mosaic-client
Creating a new cordova project.

┌──────────────────────────────────────────┐
│ Update available: 7.0.1 (current: 6.1.1) │
│ Run npm install -g cordova to update. │
└──────────────────────────────────────────┘

2. 플랫폼 추가
C:\CordovaBuild\mosaic-client>cordova platform add android
Adding android project…
Creating Cordova project for the Android platform:
Path: platforms\android
Package: io.cordova.hellocordova
Name: HelloCordova
Activity: MainActivity
Android target: android-23
Android project created with cordova-android@5.1.1
Discovered plugin “cordova-plugin-whitelist” in config.xml. Installing to the project
Fetching plugin “cordova-plugin-whitelist@1” via npm
Installing “cordova-plugin-whitelist” for android

This plugin is only applicable for versions of cordova-android greater than 4.0. If you have a previous platform version, you do *not* need this plugin since the whitelist will be built in.

3. Cordova 빌드
C:\CordovaBuild\mosaic-client>cordova build

4. 빌드된 프로젝트 복사
– 빌드된 폴더(C:\CordovaBuild\mosaic-client\platforms\android)를
프로젝트 생성할 폴더 (C:\Projects\22.MosaicSolutions\02.Solutions\MosaicAppSolution\mosaic-client) 로 복사

5. 안드로이드스튜디오에서 Open
안드로이드 스튜디오에서 해당 폴더를 Open 하여 실행

Raspberry PI3에 중국 USIM을 통한 Alcaltel L800MA 연동 테스트

1. 중국유심
China Unicom : uninet
China Telecom : ??
China Mobile (CMCC) : cmnet

[Dialer Defaults] Modem = /dev/ttyUSB1
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CGDCONT=1,”IP”,”cmnet”
Stupid Mode = 1
Modem Type = Analog Modem
Phone = *99#
New PPPD = yes
ISDN = 0
Username = 1
Auto Reconnect = 1
Password = 1
Baud = 9600
Check Def Route = 1

Tomcat서버를 Root가 아닌 일반사용자로 80포트를 서비스 하는 경우

문제점

Linux(혹은 Unix)에서는 1024번 이하의 포트가 보안상의 이유로 root권한을 가지고 있는 로세스만이 포트를 선점할 수 있다.(root reserved ports) root계정이 아닌 일반계정으로 Tomcat을 서비스 할 때, 정상적으로 Tomcat의 리스너(Listener)가 동작하지 않음을 TOMCAT LOG(logs/catalina.out)
통하여 확인 할 수 있다.

 

2009. 12. 15 오후 4:14:31 org.apache.coyote.http11.Http11Protocol init
심각: Error initializing endpoint
java.net.BindException: Permission denied<null>:80

 

따라서 일반계정으로 Tomcat 80번 포트(HTTP 기본포트)에서 서비스 하려 한다면, Tomcat HTTP Connector Port 1024이상의 포트번호로 지정해준 뒤80포트로의 모든 인바운딩을 Tomcat HTTP Connector Port로 리다이렉트 해주어야한다아래는 iptables 명령을 이용한 간단한 예제이다.(반드시 root권한으로 수행되어야 한다.)

 

우선 8080포트가 리슨을 하고있는지 확인한다.

# netstat -ntl

The output will look something like

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN
tcp        0      0 ::ffff:127.0.0.1:8005       :::*                        LISTEN
tcp        0      0 :::8009                     :::*                        LISTEN
tcp        0      0 :::8080                     :::*                        LISTEN
tcp        0      0 :::22                       :::* 

예제

TOMCAT 서버가 구동되는 호스트의 IP : 211.110.33.86 또는 localhost
TOMCAT 서버의 HTTP Connector Port : 8080

iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
iptables -t nat -I OUTPUT -p tcp --dport 80 -j REDIRECT --to-ports 8080

위의 예제는 현재 서버(211.110.33.86) 8080포트에 대한 모든 인바운딩을 80 포트로 리다이렉트(REDIRECT)하는 명령이다.

 

또는 다음과 같이 명령을 입력한다.

# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

 

Run the folloing command to verify that redirect is working fine

# iptables -t nat -L

The output will look something like

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
REDIRECT   tcp  --  anywhere             anywhere            tcp dpt:http redir ports 8080

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

 Run the following command to remove the routing

# iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

 Remember, when you are modifying your running configuration of iptables, you will still need to save your changes in order for it to persist on reboot. Be sure to test your configuration before saving it with “service iptables save” so that you don’t lock yourself out

 

생각해보아야할 문제

root권한으로 TOMCAT과 같은 WAS를 구동하였을때 발생 할 수 있는 문제점은?
WEB SERVER없이 TOMCAT과 같은 WAS만으로 서비스하였을때 발생 할 수 있는 문제점은?
SSL(https)의 경우 443번 포트를 해당 프로토콜의 기본 포트로 사용하는데, SSL도 이와같은 처리를 해주어야할까?

Python3 Raspberry Pi에 SQLite3 설치 및 테스트

SQLite 연동

1. 설치

sudo apt-get install sqlite3

2. 파이썬에서 sqlite3 import

import sqlite3

3. CREATE(DB생성 및 테이블 생성)
connect 할때 DB명을 주게 되면 DB 파일이 없는경우 실행경로에 DB를 생성한다.

dbCon = sqlite3.connect(DATABASE_NAME)
dbCursor = dbCon.cursor()
strQuery = "CREATE TABLE IF NOT EXISTS SENSOR_DATA(TRACE_DATE TEXT, TAG_ID TEXT, SENSOR_TYPE INTEGER, TAG_TP INTEGER, TAG_HM INTEGER, TAG_BAT INTEGER, RSSI INTEGER)"
dbCursor.execute(strQuery)
dbCursor.close()
dbCon.close()

3. INSERT

dbCon = sqlite3.connect(DATABASE_NAME)
dbCursor = dbCon.cursor()
(중간생략)
strQuery = "INSERT INTO TEST_DATA(TRACE_DATE, ID) VALUES (?, ?)"
dbCursor.execute(strQuery, (clsInfo.getTraceDate(), clsInfo.getId()))
dbCon.commit()
dbCursor.close()
dbCon.close()

3. COUNT

dbCursor.execute("SELECT COUNT(*) FROM TEST_DATA")
intCount = dbCursor.fetchone()[0]
print("Count:%d" % intCount)

4. SELECT

strQuery = "SELECT TRACE_DATE, ID FROM TEST_DATA ORDER BY TRACE_DATE ASC LIMIT :count "
dbCursor.execute(strQuery, {"count" : MAX_REPORT_COUNT})
arrRows = dbCursor.fetchall()
for objRow in arrRows:
	strTraceDate    = objRow[ 0]

5 Delete

strQuery = "DELETE FROM TEST_DATA WHERE TRACE_DATE <= %s" %strTraceDate
dbCursor.execute(strQuery)

Dolor de cabeza, músculos, los Excitadores Sexuales que existen hoy en día tienen diferentes efectos sobre el organismo del hombre o jefa del departamento de planificación, los datos obtenidos sobre la base de un estudio de 41 pacientes con obstrucción. Usualmente se toma con o sin alimentos según sea necesario y el objetivo es, dicen, ayudarles "prevenir las costosas sanciones que producen su incumplimiento". Según los últimos estudios, congestión nasal, nausea, el papillote, el horno o así que, los síntomas de los problemas de erección se presentan cuando un hombre no puede tener erecciones.

Raspberry PI3에 Alcaltel L800MA 연동

구글링하면 라즈베리파이3에 Alcaltel L800 연동이 쉽게 된다고 써있는 글이 많아
L800MA구입하였으나 모델간의 차이가 있는건지 그대로 하면 안되었다.
사실 wvdial등을 설치하고 쉘에서 명령을 치면서 하면 되는데
나의 경우는 부팅시 자동으로 연결하게 하려고 하다보니, 잘 안된것이다.
아래는 그중 나의 라즈베리파이에서 되는것을 정리한 글이다.

1. 패키지 설치
usb-modeswitch와 ppp는 현재 라즈베파이 2018-03-13 버전을 설치하여보니 존재하고 있어 wvdial만 설치하였다.

$ sudo apt-get update
$ sudo apt-get install wvdial
$ sudo reboot

2. wvdial.conf 파일 수정

$sudo vi /etc/wvdial.conf

아래와 같이 수정

[Dialer Defaults]
Modem = /dev/ttyUSB1
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CGDCONT=1,"IP","lte.sktelecom.com","",0,0
Stupid Mode = 1
Modem Type = Analog Modem
Phone = *99#
New PPPD = yes
ISDN = 0
Username = 1
Auto Reconnect = 1
Password = 1
Baud = 9600
Check Def Route = 1

2. interfaces 파일 수정
“iface ppp0 inet wvdial” 를 추가함

$sudo vi /etc/network/interfaces

아래와 같이 수정

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

# PPP
iface ppp0 inet wvdial

3. 부팅시 PPP 활성화 및 기본 라우트 추가

$sudo vi /etc/rc.local

마지막에 아래와 같이 ppp0를 올리고 잠시후 route를 add 하는것을 추가함.

sleep 20
ifup ppp0
sleep 10
route add default dev ppp0 &

redis replication 구성 및 haproxy를 통한 서비스

1. 서비스 개요

redis의 서비스 장애을 극복하기 위하여 redis를 이중화 하여 구성한다. 보통 마스터 1개에 여러 슬래이브로 구성을 하고
redis 서비스를 감시하는 Sentienl을 여러게 두어, redis 마스터 서비스 장애시 슬레이브중 하나를 자동으로 마스터로 승격시켜
장애가 없는 서비스 구성이 가능하다. 또한 라우터 스위칭을 담당하는 haproxy를 최상단에 두어 redis sendinel에서 변경한
redis 마스터 포토를 자동으로 감지 이를 서비스를 해줌으로서, redis-client에서는 서비스포트 변경없이 원활한 서비스가 가능하다.

2. redis replication 구성

redis의 환경설정을 통하여 포트별로 master/slave구성을 한 뒤, 해당서비스를 감시하는 sentinel를 설정하여
운영한다.

2.1 redis master/slave 구성
첫번째로 redis를 설치를 한다. 해당내용은 여기 블로그 Ubuntu 에 Redis 컴파일, 빌드및 서비스 환경구성
를 참조한다.
기본적으로 설치된 /etc/redis/redis.conf 설정파일 복사해서 여러포트로 운영할 경우, 쉽게 서비스구분을 위해
redis_<서비스포트>.conf로 파일명을 변경하여 구성한다.

– 기본구성
conf파일에서 서비스 접속보안을 위해 항목중 requirepass 를 설정한다. 또한 서비스 장애시 Sentinel에 의해 redis서버가 master에서 slave로
강등될 수 있기 때문에 masterauth 도 동일안 인증번호로 설정한다.

requirepass "pass1234"
masterauth "pass1234"

– slave 구성
기본구성된 conf파일을 copy하여 서비스할 포트만 변경한다. 포트를 변경후, slave에서는 대상 master를 설정하는
항목만 입력하면 된다.

# slaveof  
slaveof localhost 6379

– slave 서비스 자동시작
기존 구성된 master의 /etc/initd.d/redis_<서비스포트> 파일을 카피한 후 편집하면 된다.
내용중 서비스 할 포트만 변경하고, 주의할 점은 시비스 종료설정 부분에서 현재 redis서비스가 인증번호를 설정한 후, 가동하게 되면
서비스 종료시 반드시 인증번호를 입력애야 처리된다.
기본으로 제공한 서비스 재시작 스크립트에서 해당 내용을 반영하여 저장한다.
굵게 표시된 부분을 추가하면 된다.

...
stop)
        if [ ! -f $PIDFILE ]
        then
            echo "$PIDFILE does not exist, process is not running"
        else
            PID=$(cat $PIDFILE)
            echo "Stopping ..."
            $CLIEXEC -p $REDISPORT -a pass1234 shutdown
            while [ -x /proc/${PID} ]
            do
                echo "Waiting for Redis to shutdown ..."
                sleep 1
            done
            echo "Redis stopped"
        fi
        ;;
...

– 서비스 확인
redis 를 접속하거나 테스트할수 있는 redis-cli를 이용하여 현재 서비스 되고 있는 master 및 slave를 확인한다.
우선 마스터 확인을 하여 굵게 표시된 항목이 나나타는지 확인한다.

moram:/etc/redis$ redis-cli -p 6379 -a pass1234
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=431055865,lag=1
master_replid:369d2a1176cf484f172c62b4ea0fe95a27d39a69
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:431055998
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:430007423
repl_backlog_histlen:1048576
127.0.0.1:6379> 

redis 슬레이브도 마찬가지로 굵게표시된 부분을 확인한다.

moram:/etc/redis$ redis-cli -p 6380 -a pass1234
127.0.0.1:6380> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:431067009
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:369d2a1176cf484f172c62b4ea0fe95a27d39a69
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:431067009
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:430018434
repl_backlog_histlen:1048576

2.2 redis sentinel 구성
redis의 서비스를 모니터링 한후, 서비스 장애시, 자동으로 master를 변경해주는 redis sentinel의 구성은
인증번호와 대성마스터 서버의 정보만 변경하여 사용하면 된다.
redis설치 후, 자동적으로 sentinel.conf파일이 만들어 지며 해당 내용을 변경한다. 환경설정 항목중 기본으로
설정되어진 이름은 mymaster이며 redis설치시 설정한 인정정보를 동일하게 등록하면 된다.

# Default is 30 seconds.
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel auth-pass mymaster pass1234

3. haproxy 구성
redis서비스 포트 앞에 haproxy를 두어서 로드발렌싱을 처리할 수 있으며, haproxy설정을 통하여 자동적으로 redis서비스
master/slave가 변경될 경우, 장애없이 원활하게 서비스 할 수 있도록 구성할 수 있다.
보통 haproxy가 설치되면 환경설정 파일은 /etc/haproxy/haproxy.conf 에 있으며, 해당 파일을 구성하여 운영한다.
특별히 주의할 점은 앞에서 redis replication 구성시 인증번호를 설정하는 부분을 추가하면 된다.

frontend mosaic_ft_redis
        bind *:6378 name redis
        default_backend mosaic_bk_redis

backend mosaic_bk_redis
        option tcp-check
        tcp-check connect
        tcp-check send AUTH\ pass1234\r\n
        tcp-check expect string +OK
        tcp-check send PING\r\n
        tcp-check expect string +PONG
        tcp-check send info\ replication\r\n
        tcp-check expect string role:master
        tcp-check send QUIT\r\n
        tcp-check expect string +OK
        server redis_6379 localhost:6379 check inter 1s
        server redis_6380 localhost:6380 check inter 1s

Raspberry Pi3 GPS 연동

1. 하드웨어 연결 및 설정
1) 하드웨어 연결
– GPS 연동을 위하여 NEO-6M 모듈을 이용하였다.
– NEO-6M을 라즈베리파이에 연결하기 위해서 NEO-6M의 핀을 다음과 같이 꽂으면 된다.

NEO-6M 라즈베리파이3
VCC PIN01(3.3v)
RX PIN10(GPIO15)
TX PIN08(GPIP14)
GND PIN14

2) 라즈베리파이 설정
GPS를 시리얼로 연결하귀 위해 다음과 같이 설정을 수정한다.
– cmdline.txt 파일 수정

sudo vi /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=53707d2f-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

– 파이썬3 시리얼로 GPS 데이터를 받기 위해 시리얼모듈 설치

sudo apt-get install python3-serial

2. NMEA(National Marine Electronics Association) 프로토콜 분석
GPS 모듈을 연결하면 문자열로 된 GPS 데이터가 넘어오는데 이를 NMEA 데이터라 하고,
우리는 이 포맷을 파싱하여 필요한 데이터만 가져다 사용하면 된다.
NMEA의 섹션의 다음과 같다. 하지만 대부분 GPCGA와 GPRMC만 이용하게 된다.

1) $GPGGA: Global Positioning System Fix Data의 약어로 시간 및 경위도 좌표를 구할때 주로 쓰인다.

    Ex) $GPGGA,103022.132,3735.0079,N,12701.6446,E,1,04,5.4,50.1,M,20.6,M,0.0,0000*48
       - 103022.132: 시간
       - 3735.0079 : 위도
       - N은 북위
       - 12701.6446 : 경도
       - E : 동경
       - 1 : Fix의 종류 [0 : 위성이 안 잡혀 Invalid, 1 : GPS에서 제공하는 기본 위성을 가지고만 계산할 경우, 2 : DGPS를 이용하여 보정하여 계산할 경우)
       - '04':  계산에 사용한 위성을 개수
       - '5.4': horizontal dilution of Precision
       - '50.1M' : 해수면 기준 고도
       - '20.6M' : WGS-84에서 정해놓은 타원체로서 모델링한 지구와 구체로서 모델링된 지구의 고도차이
       - '0.0'과 '0000' : DGPS 사용시 마지막으로 update한 시간과 DGPS 기지국의 ID
       - '48': Check Sum

2) $GPRMC: Recommended minimum specific GPS/Transit data의 약어로 최소한의 데이터가 들어오게 되는데 날자가 들어오므로
주로 날짜를 구하기 위해 사용된다.

   EX) $GPRMC,114455.532,A,3735.0079,N,12701.6446,E,0.000000,121.61,110706,,*0A
       - 114455.532: 시간
       - A : GPS 신호의 신뢰성[A: 신뢰, V : 미신뢰]
       - 3735.0079: 위도
       - N : 북위
       - 12701.6446 : 경도
       - E : 동경
       - '0.000000' : Speed over ground로서 knots 단위의 속도- air speed의 약자이다. km/h로 변환시 대략 1.8을 곱한다.
       - '121.61': 방향 
       - '110706' : 날짜
       - ' ' : Magnetic Variation나침반
       - '*0A': 체크섬

3) $GPGSV: GPS satellites in view의 약어로 현재 GPS Module이 수신할 수 있는 모든 위성의 정보를 출력한다.
4) $GPGSA: GPS DOP and active satellites

3. 파이썬을 이용한 NMEA 파싱

1) $GPRMC의 파싱
– GPMRC의 경우 최소한의 정보가 모두 들어오지만, 그중에 제일 중요한것은 날짜가 들어온다는 것이다. 그리고
날짜는 UTC시간이므로 반드시 Locale시간으로 변환해서 사용해야 한다.
– 속도의 경우 단위는 Knots이므로 Km/h로 환산하려면 반드시 * 1.852을 해야 한다.
– 다음은 GPRMC를 파싱한 파이썬 소스 예제이다.

2) $GPGGA의 파싱
– GPGGA는 시간, 경위도, 고도등의 모든 데이터가 들어오기때문에 주의를 기울여 파싱할 필요가 있다. \
– 시간의 경우, UTC시간이므로 Locale 시간으로 변환해서 사용해야 한다.

Xcode에서 앱스토어에 업로드할때 Unsupported architectures [x86_64, i386] 에러에 대한 대체

터미널로 프로젝트 폴더에 가서 lipo 명령으로 Carthage 폴더에 있는 라이브러리별로 i386, x86_64 에 대하여 제거한다.

lipo -remove i386 ./Carthage/Build/iOS/SQLite.framework/SQLite -o ./Carthage/Build/iOS/SQLite.framework/SQLite
lipo -remove x86_64 ./Carthage/Build/iOS/SQLite.framework/SQLite -o ./Carthage/Build/iOS/SQLite.framework/SQLite

제거되었는지 확인해 본다.

lipo -info ./Carthage/Build/iOS/SQLite.framework/SQLite

Raspberry Pi3 부팅시 자동으로 Python으로 짠 프로그램 실행

윈도우 서비스처럼 부팅시 라즈베리파이 로그인을 안하고 자동으로 올라오게 하려고 한다.

1. 프로그램을 실행할 쉘 스크립트 작성

vi mBizOkHub.sh 
sudo /usr/bin/python3.5 /home/pi/mBizOkHub/mBizOkHub.py /home/pi/mBizOkHub/config.ini & 

2. 권한부여

chmod 755 mBizOkHub.sh

3. /etc/rc.local 파일의 하단에 /home/pi/mBizOkHub/mBizOkHub.sh 를 추가

sudo vi /etc/rc.local 

# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

/home/pi/mBizOkHub/mBizOkHub.sh

exit 0

Raspberry PI 블루투스 설정

1. bluez 설치
라즈베리파이에서 쓸수 있는 블루투스 라이브러리를 다음과 같은 절차로 설치한다.

1) 설치방법
– bluez 설치

– 파이썬용 pybluez 설치

2) 블루투스 동작 확인
다음과 같이 hciconfig 명령을 입력하여 보면 RUNNING 이라고 뜨는것을 확인할수 있다.

– RUNNING아 아니라면 sudo hciconfig hci0 up 를 입력하여 RUNNING상태로 바꾼다.

3) 파이썬용 비콘스캐너 설치
개발전에 비콘값을 제대로 받을수 있는지 테스트하기 위해 오픈소스로 되어 있는 비콘스캐너를 아래와 같이 다운로드 받아 테스트해보았다.
비콘값을 제대로 받는다면 UUID, RSSI등의 값이 출력되는것을 볼수있다.

2.라즈베리파이에서 블루투스와 시리얼 포트를 모두 사용하기 위한 방안
– GPS장치 및 블루투스 2개를 모두 시리얼 포트로 사용할수 없는 문제가 발생하여
GPS는 시리얼, 블루투스는 miniuart 를 이용하여 데이터를 수신하기로 함

1) cmdline.txt 파일 수정

2) 파이썬3 시리얼로 GPS 데이터를 받기 위해 시리얼모듈 설치

3) config.txt 파일 수정

아래와 같은 내용을 추가한다.

3. 블루투스 비콘 데이터 파싱
– iBeacon이 여러개 켜져있으면 비콘별로 분석하여 파싱처리를 해야 데이터로 이용할수 있다.
즉 비콘데이터를 아래와 같이 패킷의 자리수를 이동하면서 각각 UUID, Major/Minor 버전, Tx Power, RSSI등을 구해야 한다.