webOS 프로젝트

webOS를 활용한 HomeIoT : 조명제어2 - Enact App

하이하정 2021. 11. 27. 13:38

 

  • 전체 시스템 소개
  • 조명 제어
  • 스마트 가습기
  • 수면 패턴 분석
  • 시스템 연동

 

Enact webapplication 개발하기


1. Enact 기본 앱 만들기

Enact webapplication의 설치 및 Enact App개발 시작에 관한 것은 기존게시글을 참고해주세요.

 

2. webapplication의 ui 디자인

ui

위 사진처럼

1. 각 방의 전등을 제어,

2. 모든 방의 전등을 한번에 제어

할 수 있게 ui를 짰습니다. 

 

3. LightPanel.js  전체 코드

main 코드인 Main.Panel.js 파일의 전체 코드입니다.

import './LightPanel.style.css';
import {useEffect, useState} from 'react';
import React from 'react';
import Button from '@enact/sandstone/Button';
import LS2Request from '@enact/webos/LS2Request';

var bridge = new LS2Request();
const serviceUrl = 'luna://com.cosmos.project.service';

const lsSetLedStatus = (deviceID, ledStatus) => {
   let request = {
      service: serviceUrl,
      method: 'setLedState',
      parameters: {deviceID:deviceID, value:ledStatus},
      onSuccess: (msg) => {console.log('onSuccess-lsSetLedStatus', msg);},
      onFailure: (msg) => {console.log('onFailure-lsSetLedStatus', msg);},
   };
   bridge.send(request);
};
 
function MoonOn() {
   return (
      <div id="moonon">on</div>
   );
}

function MoonOff() {
   return (
      <div id="moonoff">off</div>
   );
}

function Moon(props) {
   return (
      <>
      <div id="moonclick">
      {
         props.ledState
         ? <MoonOn></MoonOn>
         : <MoonOff></MoonOff>
      }
      </div>
      </>
   );
}

const LightPanel = () => {
   let [led1, setLed1] = useState(false);
   let [led2, setLed2] = useState(false);
   let [led3, setLed3] = useState(false);
   let [led4, setLed4] = useState(false);
   let [led5, setLed5] = useState(false);

   const lsGetStauts = () => {
      let request = {
         service: serviceUrl,
         method: 'getLedStates',
         parameters: {},
         onSuccess: (msg) => {
            console.log('onSuccess-lsGetStauts', msg);
            setLed1(msg.data['LED01']);
            setLed2(msg.data['LED02']);
            setLed3(msg.data['LED03']);
            setLed4(msg.data['LED04']);
            setLed5(msg.data['LED05']);
         },
         onFailure: (msg) => {console.log('onFailure-lsGetStauts', msg);},
      };
      bridge.send(request);
   }
   lsGetStauts();

   const setStatusAll = (value) => {
      setLed1(value);
      setLed2(value);
      setLed3(value);
      setLed4(value);
      setLed5(value);

      lsSetLedStatus('LED01', value);
      lsSetLedStatus('LED02', value);
      lsSetLedStatus('LED03', value);
      lsSetLedStatus('LED04', value);
      lsSetLedStatus('LED05', value);
   };  

    return (
      <>
      <div id="wrap">
         <div className="box" id="abs1" onClick={()=>{lsSetLedStatus('LED01', !led1); setLed1(!led1); }}>
            침실
            <Moon ledState={led1}></Moon>
         </div>
         <div className="box" id="abs2" onClick={()=>{lsSetLedStatus('LED02', !led2); setLed2(!led2); }}>
            방
            <Moon ledState={led2}></Moon>
         </div>
         <div className="box" id="abs3" onClick={()=>{lsSetLedStatus('LED03', !led3); setLed3(!led3); }}>
            욕실
            <Moon ledState={led3}></Moon>
         </div>
         <div className="box" id="abs4">주방</div>
         <div className="box" id="abs5" onClick={()=>{lsSetLedStatus('LED04', !led4); setLed4(!led4); }}>
            거실
            <Moon ledState={led4}></Moon>
         </div>
         <div className="box" id="abs6" onClick={()=>{lsSetLedStatus('LED05', !led5); setLed5(!led5); }}>
            테라스
            <Moon ledState={led5}></Moon>
         </div>
      </div>
      <div id="button-section">
         <Button size="small" onClick={()=>{setStatusAll(true);}}>전체 점등</Button>
         <Button size="small" onClick={()=>{setStatusAll(false);}}>전체 소등</Button> 
      </div>
      </>
   );
};

export default LightPanel;

 

4. LightPanel.style.css 전체 코드

Main.Panel.js 의 구성들을 디자인해주는 Main.Panel.style.css 파일의 전체 코드입니다.

.main-container {
    margin: auto;
    display: grid;
    grid-template-columns: 40% 60%;
    gap: 10px; /* 구역간의 간격 */
}
#wrap {
    left: 1000px;
    position: absolute;
    width: 1200px;
    height: 900px;
    border: 3px solid rgb(160, 159, 159);
}
.box {
    position: absolute;
    margin : 0;
    border: 1px solid rgb(160, 159, 159);
    font-size: 17pt;
}
#abs1 {
    top:0; left:0;
    width: 25%;
    height: 50%;
}
#abs2 {
    bottom:0; left:0;
    width: 25%;
    height: 50%;
}
#abs3 {
    top: 0; left:25%;
    width: 25%;
    height: 50%;
}
#abs4 {
    top: 0; left: 50%;
    width: 25%;
    height: 50%;
}
#abs5 {
    bottom:0; left:25%;
    width: 50%;
    height: 50%;
}
#abs6 {
    top:0; left:75%;
    width: 25%;
    height: 100%;
}
#moonclick {
    position: absolute;
    top: 30%;
    right: 25%;
    width:150px;
    height:150px;
    text-align:center;
    font-size:12px;
    vertical-align:middle;
    line-height:150px;
}
#moonon {
    position: absolute;
    background-color:#e7e97a;
    width:150px;
    height:150px;
    border-radius:75px;
    text-align:center;
    font-size:30px;
    color: black;
    vertical-align:middle;
    line-height:150px;
}
#moonoff {
    position: absolute;
    background-color:rgba(255, 255, 255, 0.568);
    width:150px;
    height:150px;
    border-radius:75px;
    text-align:center;
    font-size:30px;
    vertical-align:middle;
    line-height:150px;
}
.box-three {
    padding-top:100px;
    display: flex;
    flex-direction: column; /* 세로 정렬 */
    border: none; /* border를 지우고 3-1과 3-2에 각각 border를 적용해줍니다. */
}
#button-section {
    left: 295pt;
    position: absolute;
    margin-top: 960px;
    margin-left: 620px;
}

 

5. MainPanel.js 코드 구성

  • 필요한 기능을 import

Button, LS2Request 등 기능을 사용하고 css를 적용할 수 있도록 MainPanel.js에 아래의 코드를 추가합니다. 

import kind from '@enact/core/kind';
import {Panel, Header} from '@enact/sandstone/Panels';
import {useEffect, useState} from 'react';
import React from 'react';
import Button from '@enact/sandstone/Button';
import LS2Request from '@enact/webos/LS2Request'; //service 요청시 필요한 코드
import './MainPanel.style.css'

 

 

  • 서비스 관련 변수, 함수

server와 ESP에 정보 전달을 위해

var bridge = new LS2Request();
const serviceUrl = 'luna://com.cosmos.project.service';

위의 코드를 먼저 추가해줍니다.

그리고 밑의 함수를 추가해줍니다.

  • IsSetLedStatus 함수
const lsSetLedStatus = (deviceID, ledStatus) => {
   let request = {
      service: serviceUrl,
      method: 'setLedState',
      parameters: {deviceID:deviceID, value:ledStatus},
      onSuccess: (msg) => {console.log('onSuccess-lsSetLedStatus', msg);},
      onFailure: (msg) => {console.log('onFailure-lsSetLedStatus', msg);},
   };
   bridge.send(request);
};

변수가 deviceID, ledStatus인 서비스에 정해진 정보를 전달해주는 함수입니다.

server에 전달해줄 정보가 request에 담겨있습니다.

deviceID : 각 전등마다 맞는 deviceID를 지정해줍니다.

ledStatus : 각 전등의 on/off 상태를 나타내줍니다.

 

  • IsGetStatus 함수
const lsGetStauts = () => {
      let request = {
         service: serviceUrl,
         method: 'getLedStates',
         parameters: {},
         onSuccess: (msg) => {
            console.log('onSuccess-lsGetStauts', msg);
            setLed1(msg.data['LED01']);
            setLed2(msg.data['LED02']);
            setLed3(msg.data['LED03']);
            setLed4(msg.data['LED04']);
            setLed5(msg.data['LED05']);
         },
         onFailure: (msg) => {console.log('onFailure-lsGetStauts', msg);},
      };
      bridge.send(request);
   }
   lsGetStauts();

led의 상태를 server를 통해 가져오는 함수입니다.

led상태를 가져와 led변수들에 저장해줍니다.

 

 

  • 전등의 On/Off 의 상태를 나타내주는 함수

전등의 On/Off 상태 변화를 나타내주기 위한 함수들입니다.

위치와 디자인은 css를 참조합니다.

  • 전등을 켰을 때의 상태를 나타내주는 함수 MoonOn()
  • function MoonOn() { return ( <> <div id="moonon">on</div> </> ); }

 

  • 전등을 껐을 때의 상태를 나타내주는 함수 MoonOff()
  • function MoonOff() { return ( <> <div id="moonoff">off</div> </> ); }

 

  • onClick 이벤트를 이용해 전등의 On/Off 상태를 바꿔주는 함수 Moon()
function Moon(props) {
   let [star, starChange] = useState(false);
   
   useEffect(()=>{
      starChange(props.sa);
   }, [props.sa]);

   useEffect(()=>{
      props.settext(star);
   }, [star]);

   return (
      <> 
         <div id="moonclick" onClick={()=>{star?starChange(false):starChange(true);props.settext(star); }}>
                        {
               star
               ? <MoonOn></MoonOn>
               : <MoonOff></MoonOff>
            }
         </div>
      </>
   );
 }

useState를 이용하여 star라는 변수에 전등이 on일 때 true, off일 때 false 변수를 저장합니다.

(props는 MyPannel함수에서 함께 설명)

MoonOn()
MoonOff()

클릭 시 두 이미지중 하나로 바뀝니다.

 

  • LightPannel()

위의 설명한 함수들과 다른 요소들을 추가하여 적절히 배치해줍니다.

위치와 디자인은 css를 참조합니다.

const LightPanel = () => {
   let [led1, setLed1] = useState(false);
   let [led2, setLed2] = useState(false);
   let [led3, setLed3] = useState(false);
   let [led4, setLed4] = useState(false);
   let [led5, setLed5] = useState(false);

   const lsGetStauts = () => {
      let request = {
         service: serviceUrl,
         method: 'getLedStates',
         parameters: {},
         onSuccess: (msg) => {
            console.log('onSuccess-lsGetStauts', msg);
            setLed1(msg.data['LED01']);
            setLed2(msg.data['LED02']);
            setLed3(msg.data['LED03']);
            setLed4(msg.data['LED04']);
            setLed5(msg.data['LED05']);
         },
         onFailure: (msg) => {console.log('onFailure-lsGetStauts', msg);},
      };
      bridge.send(request);
   }
   lsGetStauts();

   const setStatusAll = (value) => {
      setLed1(value);
      setLed2(value);
      setLed3(value);
      setLed4(value);
      setLed5(value);

      lsSetLedStatus('LED01', value);
      lsSetLedStatus('LED02', value);
      lsSetLedStatus('LED03', value);
      lsSetLedStatus('LED04', value);
      lsSetLedStatus('LED05', value);
   };  

    return (
      <>
      <div id="wrap">
         <div className="box" id="abs1" onClick={()=>{lsSetLedStatus('LED01', !led1); setLed1(!led1); }}>
            침실
            <Moon ledState={led1}></Moon>
         </div>
         <div className="box" id="abs2" onClick={()=>{lsSetLedStatus('LED02', !led2); setLed2(!led2); }}>
            방
            <Moon ledState={led2}></Moon>
         </div>
         <div className="box" id="abs3" onClick={()=>{lsSetLedStatus('LED03', !led3); setLed3(!led3); }}>
            욕실
            <Moon ledState={led3}></Moon>
         </div>
         <div className="box" id="abs4">주방</div>
         <div className="box" id="abs5" onClick={()=>{lsSetLedStatus('LED04', !led4); setLed4(!led4); }}>
            거실
            <Moon ledState={led4}></Moon>
         </div>
         <div className="box" id="abs6" onClick={()=>{lsSetLedStatus('LED05', !led5); setLed5(!led5); }}>
            테라스
            <Moon ledState={led5}></Moon>
         </div>
      </div>
      <div id="button-section">
         <Button size="small" onClick={()=>{setStatusAll(true);}}>전체 점등</Button>
         <Button size="small" onClick={()=>{setStatusAll(false);}}>전체 소등</Button> 
      </div>
      </>
   );
};코드

 

이 함수 안에서 각각의 전등의 On/Off 상태를 나타내기 위해 useState로 각각의 변수를 만들고 자식 함수 Moon()에서 전등 변수 상태값(True or False)를 props를 이용하여 가져와 각 변수에 저장해줍니다.

(server에 상태를 전달하기 위해)

 

또한 전체 전등을 제어해야하기 때문에 반대로 props로 자식 함수 Moon()에 넘겨주어 모든 전등 변수의 상태를 True / False 로 바꾸게 해줍니다.

  • 전체 led 제어 함수
const setStatusAll = (value) => {
      setLed1(value);
      setLed2(value);
      setLed3(value);
      setLed4(value);
      setLed5(value);

      lsSetLedStatus('LED01', value);
      lsSetLedStatus('LED02', value);
      lsSetLedStatus('LED03', value);
      lsSetLedStatus('LED04', value);
      lsSetLedStatus('LED05', value);
   };
	<Button size="small" onClick={ ()=>{statusAllChange(true);}}>전체 점등</Button>
	<Button size="small" onClick={ ()=>{statusAllChange(false);}}>전체 소등</Button>

 

Button을 넣어 클릭시 모든 led 변수를 True or False 로 바꾸게 해주었습니다