ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [WEB 개발] 001 라즈베리 파이와 nodejs로 만드는 timer
    Program development/web 2021. 6. 4. 01:06

    이번에는 요청이 들어와서 개발과정을 정리하고 요약하며 정보를 전달드리고자합니다

    목표 : nodejs 를 이용한 정말 간단한 timer 프로그램 개발

    이 페이지를 통해 아래 정보를 확인하실 수 있습니다. 

    1. 최종결과물 확인
    2. nodejs 개발환경 구축하기
    3. port 설정하기
    4. jade를 이용한 view 구현
    5. javascript 를 이용한 timer code 구현
    6. javascript 를 이용한 sound code 구현
    7. javascript 를 이용한 sound + timer code 구현
    8. nohup 으로 세션이 닫혀도 실행되게 만들기
    9. 최종코드

    최종결과물 확인

    먼저 만들고자하는 결과물부터 확인하실 수 있도록 링크를 연결해 두겠습니다.

    아래 링크는 항상 서비스하는 프로그램은 아닙니다.

    http://mgpark1102.iptime.org:33002/


    nodejs 개발환경 구축하기

    node js 와 express가 설치되어 있다고 가정하고 진행하겠습니다. 

     

    먼저 express 명령어를 통해 개발환경을 설정해 주어야 합니다. 

    mkdir timer
    cd timer
    express ./
    npm install

    기본적인 개발 환경이 구성되었습니다. 

    만약 samba를 설정하여 필자와 개발환경을 동일하게 구성하고 싶으시다면 추후에 작업해 올려드리겠습니다. 


    port 설정하기

    기본으로 생성된 (프로젝트폴더)/app.js 파일에 41번째 줄에 port를 열어주도록 설정합니다.

    var port = 3002;
    app.listen(port, () => {
      console.log(`Example app listening at http://localhost:${port}`)
    })

    합쳐지면 아래와 같습니다. 

    var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');
    
    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    
    var app = express();
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.use('/', indexRouter);
    app.use('/users', usersRouter);
    
    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
      next(createError(404));
    });
    
    // error handler
    app.use(function(err, req, res, next) {
      // set locals, only providing error in development
      res.locals.message = err.message;
      res.locals.error = req.app.get('env') === 'development' ? err : {};
    
      // render the error page
      res.status(err.status || 500);
      res.render('error');
    });
    
    var port = 3002;
    app.listen(port, () => {
      console.log(`Example app listening at http://localhost:${port}`)
    })
    
    
    module.exports = app;

    이렇게 설정하게 되면 아래 명령어를 실행하였을때 express 페이지를 [rpi 주소]:3002를 실행하므로 정상적인 실행을 확인할 수 있습니다. 

    node app.js


    jade를 이용한 view 구현

    간단한 프로젝트로 backend 쪽인 node 쪽의 수정을 최소화하였습니다.

    express에서 기본적으로 제공하는 jade를 이용하여 아래와 같은 뷰를 설정해 보겠습니다. 

    view 주된 목표

    1. count up

    2. 소리 신호 주기 설정

    3. 시작 버튼

     

     (프로젝트폴더)/views/index.jade 폴더를 아래와 같이 수정하여 view 목표달성을 진행합니다.

    extends layout
    
    block content
    
      div 
        //1. count up
        span#timer 00:00:00 
    
        //2. 소리 신호 주기 설정
        p Input_interval : 
          input.HZ(type="text")
          span  s
        //3. 시작버튼 
        input.start(type="button", value ="start") 
      script(type = "module" src="/javascripts/timer.js")
      

    javascript 를 이용한 timer code 구현

    3가지 기능으로 구분하여 함수를 작성합니다.

    1. 버튼을 눌러 시작 시간을 저장하기
    2. 1초에 한번 view에서 timer 를 변경하기
    3. timer를 display 하도록 출력형식 변경하기

     

     (프로젝트폴더)/public/javascripts/timer.js

    let start  = new Date();
    let btnStart = document.querySelector(".start");
    let output = document.querySelector("#timer");

     

    1. 버튼을 눌러 시작 시간을 저장하기

    시작버튼을 눌러서 

     

    2. 1초에 한번 view에서 timer 를 변경하기

    1초마다 주기적인 실행을 위해 setInterval(function()[반복함수], [반복 주기]) 함수를 설정합니다. 

    let x = setInterval(function(){
       
        if(bstart ==0){
            output.innerHTML  = "00:00:00";
        }
        else{
            let now = new Date();
            let Time = parseInt((now.getTime()-start.getTime())/1000);
            let string = dateToString(parseInt(Time));       
            output.innerHTML  = string;
        }
    },1000); //반복주기

     

    3. timer를 display 하도록 출력형식 변경하기

    그렇다면 new Date(); 함수를 통해 만들어진 값은 어떤 값이 만들어졌을까요?

    이미 예상하셨겠지만 dateToString()이 제가 만들어둔 시간 함수입니다. 

     

    그래도! 설명을 드리고 넘어가겠습니다. time 은 [ 현재 시간 - 시작 시간 ]으로 경과시간을 담아둔 변수이며 now 는 현재시간을 의미합니다. 따라서 그 출력값들을 console.log(now,Time); 을 통해 출력해보면 아래와 같은 정보를 확인 할 수 있습니다. 

    흠 now는 복잡한 시간 정보로 보여지지만 Time의 경우 0,1... 이라는 number라는 것을 확인 할 수 있습니다.

    확인은 웹에서 F12 >> console 에서 확인 가능합니다.

     

    그렇다면 이 정보를 00:00:01 로 표현하도록 표현 함수를 작성해야합니다. 

    그 함수는 아래와 같습니다. 

    function dateToString(timer,display = 111, interval = ':'){
        
        let string = "";
        
        if(display/100 >= 1){
            string += (parseInt(timer/3600)) >= 10 ? (parseInt(timer/3600)).toString(10): '0' +(parseInt(timer/3600)).toString(10);
            string += interval;
        }
        if((display/10)%10 >= 1){
            string += (parseInt(timer/60)%60) >= 10 ? (parseInt(timer/60)%60).toString(10) : '0'+(parseInt(timer/60)%60).toString(10);
            string += interval;
        }
        if(display%10 >= 1){
        string += (timer%60) >= 10 ? (timer%60).toString(10) :'0' +(timer%60).toString(10) ;
        }
        return string;
    }

    위 함수는 시간 입력을 받으며 display변수가 111이면 시간, 분, 초 를 표시하며 110이면 시간, 분이 표시되도록 설정된 변수이며 사이 간격에서 표기 방식을 표시할수 있게 interval 을 추가했습니다. 


    javascript 를 이용한 sound code 구현

    요청받은 기능 중 핵심기능은 주기적으로 들리는 소리 기능입니다. 이 기능을 위해 하나의 js파일을 추가로 작성하여 작업을 진행하였습니다. 

    음 .. 이번 함수는 javascript 에서 객체지향을 적용하여 구현하기 위해 class를 사용했습니다. 

     

    필요한 기능을 정리하겠습니다. 

    1. Audio 초기화

    2. 소리 시작

    3. 소리 정지

     

    외부에 적용할 것이니 export을 통해 class를 생성하겠습니다.

     (프로젝트폴더)/public/javascripts/sound.js

    export default class Hz {
        constructor() {}
    
        bgm_init(){ 
            var bgm = new Audio();
            bgm.src= '/sound/dupong.mp3';
            bgm.loop= false;
            document.body.appendChild(bgm); //하위요소로 만듬.
            //setOnClick();
        }
    
        HZFunctionPlay(){
            var bgm = document.getElementsByTagName('audio');
            bgm[0].play();
        }
    
        HZFunctionStop(){
            var bgm = document.getElementsByTagName('audio');
            bgm[0].pause();
        }
        
    };
    

    (프로젝트폴더)/public/sound/dupong.mp3 가 있어야 위 코드에서 dupong.mp3를 불러올 수 있습니다. 

    Audio().src = '/sound/dupong.mp3' 라인은 Audio의 경로를 설정하는 부분입니다. 

    Audio().loop = false; 라인은 반복재생을 취소하는 부분입니다.

    document.body.appendChild(bgm); 하위요소를 만들어야 이후 다른곳에서 해당 요소에 접근할 수 있기때문에 appendChild를 통해 하위요소를 생성합니다. 

     

    클래스에 대한 기본적인 정보는 아래 링크에서 확인하실 수 있습니다. 

    https://sosohanchan.tistory.com/40

     

    [WEB 개발] 001_1 javascript 에서 class 사용하기

    "001 라즈베리 파이와 nodejs로 만드는 timer" 에서 사용한 javascript class 에 대해 알아보고자 합니다. 목표 : javascript 에서 class 사용하기 이 페이지를 통해 아래 정보를 확인하실 수 있습니다. 기본문

    sosohanchan.tistory.com


    javascript 를 이용한 sound + timer code 구현

    자 그럼 이제 마지막으로 timer 에 sound를 합쳐서 최종코드를 구현하겠습니다. 

    (프로젝트폴더)/public/javascripts/timer.js 에 코드만 추가하면 됩니다. 

    먼저 생성한 sound.js 파일을 연결해 줍니다.

     

    (프로젝트폴더)/public/javascripts/timer.js 

    import HZ from "/javascripts/sound.js"

     

    다음으로 객체를 생성하고 bgm을 초기화 시켜서 dupong.mp3를 연결하고 하위요소로 만들어줍니다. 

    var hz = new HZ();
    hz.bgm_init();

     

    간격마다 사운드가 들릴 수 있도록 setInterval 함수를 수정합니다. 5초간 dupong.mp3를 실행시키도록 아래 함수를 추가하였습니다. 

    let fAudio = 0;
    let x = setInterval(function(){
       
        let frequency = document.querySelector(".HZ");
        if(bstart ==0){
            output.innerHTML  = "00:00:00";
        }
        else{
            let now = new Date();
            let Time = parseInt((now.getTime()-start.getTime())/1000);
            if (Time % parseInt(frequency.value) < 5)
            {
                fAudio = 1;
                hz.HZFunctionPlay();
            }
            let string = dateToString(parseInt(Time));       
            output.innerHTML  = string;
        }
    },1000);

    완성!!!

    20초마다 소리나는 웹프로그램을 만들었습니다. 


    nohup 으로 세션이 닫혀도 실행되게 만들기

    라즈베리파이에서 node app.js 를 실행시켜 서버를 켜두면 터미널을 종료할때 같이 종료됩니다. 

    이는 nohup을 통해 해결할 수 있습니다. 

    nohup node app.js > app.log &
    exit

     위 코드를 실행하면 접속중인 터미널을 닫아도 라즈베리파이에서 실행되어 있는 상태가 유지되며 app.log파일에 정보가 저장됩니다.

     


    최종코드

    최종코드는 아래와 같습니다. 

    (프로젝트폴더)/app.js

    var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');
    
    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    
    var app = express();
    
    // view engine setup
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static(path.join(__dirname, 'public')));
    
    app.use('/', indexRouter);
    app.use('/users', usersRouter);
    
    // catch 404 and forward to error handler
    app.use(function(req, res, next) {
      next(createError(404));
    });
    
    // error handler
    app.use(function(err, req, res, next) {
      // set locals, only providing error in development
      res.locals.message = err.message;
      res.locals.error = req.app.get('env') === 'development' ? err : {};
    
      // render the error page
      res.status(err.status || 500);
      res.render('error');
    });
    
    var port = 3003;
    app.listen(port, () => {
      console.log(`Example app listening at http://localhost:${port}`)
    })
    
    module.exports = app;
    

    (프로젝트폴더)/views/index.jade

    extends layout
    
    block content
    
      div 
        //1. count up
        span#timer 00:00:00 
    
        //2. 소리 신호 주기 설정
        p Input_interval : 
          input.HZ(type="text")
          span  s
        //3. 시작버튼 
        input.start(type="button", value ="start") 
      script(type = "module" src="/javascripts/timer.js")
      

    (프로젝트폴더)/public/javascripts/timer.js 

    import HZ from "/javascripts/sound.js"
    let start  = new Date();
    let btnStart = document.querySelector(".start");
    let output = document.querySelector("#timer");
    
    let bstart = 0;
    btnStart.onclick = function (){
        start = new Date();
        bstart = 1;
    }
    
    var hz = new HZ();
    hz.bgm_init();
    
    let fAudio = 0;
    let x = setInterval(function(){
       
        let frequency = document.querySelector(".HZ");
        if(bstart ==0){
            output.innerHTML  = "00:00:00";
        }
        else{
            let now = new Date();
            let Time = parseInt((now.getTime()-start.getTime())/1000);
            if (Time % parseInt(frequency.value) < 5)
            {
                fAudio = 1;
                hz.HZFunctionPlay();
            }
            let string = dateToString(parseInt(Time));       
            output.innerHTML  = string;
        }
    },1000);
    
    
    
    function dateToString(timer,display = 111, interval = ':'){
        
        let string = "";
        
        if(display/100 >= 1){
            string += (parseInt(timer/3600)) >= 10 ? (parseInt(timer/3600)).toString(10): '0' +(parseInt(timer/3600)).toString(10);
            string += interval;
        }
        if((display/10)%10 >= 1){
            string += (parseInt(timer/60)%60) >= 10 ? (parseInt(timer/60)%60).toString(10) : '0'+(parseInt(timer/60)%60).toString(10);
            string += interval;
        }
        if(display%10 >= 1){
        string += (timer%60) >= 10 ? (timer%60).toString(10) :'0' +(timer%60).toString(10) ;
        }
        return string;
    }
    

    (프로젝트폴더)/public/javascripts/sound.js 

    export default class Hz {
        constructor() {}
    
        bgm_init(){ 
            var bgm = new Audio();
            bgm.src= '/sound/dupong.mp3';
            bgm.loop= false;
            document.body.appendChild(bgm); //하위요소로 만듬.
            //setOnClick();
        }
    
        HZFunctionPlay(){
            var bgm = document.getElementsByTagName('audio');
            bgm[0].play();
        }
    
        HZFunctionStop(){
            var bgm = document.getElementsByTagName('audio');
            bgm[0].pause();
        }
        
    };
    

     

    'Program development > web' 카테고리의 다른 글

    [WEB 개발] 001_1 javascript 에서 class 사용하기  (0) 2021.06.04

    댓글

Designed by Tistory.