- 전체 시스템 소개
- 조명 제어
- 스마트 가습기
- 수면 패턴 분석
- 시스템 연동
서비스 개요
1. 서비스 기능
스마트 조명은 사용자(app)으로부터 각 방 조명에 대한 On/Off 명령을 받아 각 방의 조명을 제어합니다.
또한 전체 소등/ 전체 점등 기능으로 모든 방의 조명을 한 번에 제어할 수도 있습니다.
이러한 기능을 제공하기 위해 필요한 서비스의 기능은 다음과 같습니다.
- Enact app으로부터 각 조명 On/Off 명령을 받는다
- 디바이스에게 On/Off 명령을 전달한다
2. 서비스 함수
getLedStates | 디바이스에서 On/Off 상태를 받아온다 |
setLedState | Enact app으로부터 Led1~5의 각 조명 On/Off 명령을 받아와서 디바이스에 전달한다 |
startServer | webSocket을 이용하여 양방향 통신이 가능하도록 한다 |
heartbeat | heartbeat 서비스를 이용하여 서비스가 계속해서 수행되도록 한다 |
서비스 개발
1. getLedStates
let ledStates = {
'LED01' : false,
'LED02' : false,
'LED03' : false,
'LED04' : false,
'LED05' : false,
};
service.register('getLedStates', function(message){
message.respond({
returnValue : true,
data : ledStates
});
});
service.register를 사용하여 getLedStatus 서비스를 등록합니다.
디바이스의 message에서 현재 led의 On/Off상태 value를 받아 respond합니다.
led는 총 5개로, ledStates 변수 안에 각 LED의 상태가 false(OFF)를 기본으로 저장되어있습니다.
2. setLedState
service.register('setLedState', function(message){
let deviceID = message.payload.deviceID;
ledStates[deviceID] = message.payload.value;
console.log('setLedState', ledStates);
let statusString = ledStates[deviceID] ? "on" : "off";
let command = {
msgType : "command",
deviceType : "led",
deviceID : deviceID,
status : statusString
};
broadCastMessage(JSON.stringify(command));
message.respond({
returnValue : true,
});
});
Enact App의 message에서 조명 On/Off 상태설정 value 를 얻어 각 ledStates 에 저장합니다.
저장한 값을 JSON형식으로 디바이스에 전달합니다.
3. startServer
app.use(function (req, res, next) {
console.log('middleware');
req.testing = 'testing';
return next();
});
app.ws('/', function(ws, req) {
console.log('Recieved something');
ws.on('message', handleMessage);
});
const broadCastMessage = (message) => {
aWss.clients.forEach(function (client) {
client.send(message);
});
}
service.register("startServer", function(message) {
console.log('WebSocketServer on?');
app.listen(port);
console.log('WebSocketServer on!');
// heartbeat 구독
const sub = service.subscribe(`luna://${pkgInfo.name}/heartbeat`, {subscribe:true});
// const max = 120;
// let count = 0;
sub.addListener("response", function(msg) {
console.log(JSON.stringify(msg.payload));
// if (++count >= max) {
// sub.cancel();
// setTimeout(function(){
// // console.log(max+" responses recieved, exiting...");
// process.exit(0);
// }, 1000);
// }
});
message.respond({
returnValue: true,
Response: "Start Server!"
});
});
socket server를 여는 startServer를 등록합니다.
4. heartbeat
webSocketServer 서비스가 계속해서 동작하기 위해 heartbeat를 구독해주어야 합니다.
자세한 내용은 heartbeat 사용하기 포스팅을 통해 확인해주시기 바랍니다.
// ***************************** Heartbeat *****************************
// send responses to each subscribed client
function sendResponses() {
// console.log(logHeader, "send_response");
// console.log("Sending responses, subscription count=" + Object.keys(subscriptions).length);
for (const i in subscriptions) {
if (Object.prototype.hasOwnProperty.call(subscriptions, i)) {
const s = subscriptions[i];
s.respond({
returnValue: true,
event: "beat " + x
});
}
}
x++;
}
// handle subscription requests
const subscriptions = {};
let interval;
let x = 1;
function createInterval() {
if (interval) {
return;
}
console.log(logHeader, "create_interval");
console.log("create new interval");
interval = setInterval(function() {
sendResponses();
}, 1000);
}
전체 서비스 코드
1. service.js
더보기
더보기
const pkgInfo = require('./package.json');
const Service = require('webos-service');
const service = new Service(pkgInfo.name); // Create service by service name on package.json
const logHeader = "[" + pkgInfo.name + "]";
var express = require('express');
var app = express();
var expressWs = require('express-ws')(app);
var aWss = expressWs.getWss('/');
const port = 9999;
// ***************************** Websocket Server *****************************
app.use(function (req, res, next) {
console.log('middleware');
req.testing = 'testing';
return next();
});
app.ws('/', function(ws, req) {
console.log('Recieved something');
ws.on('message', handleMessage);
});
const handleMessage = (message) => {
console.log('Recieved: ', message);
let msg = JSON.parse(message);
if (msg.msgType == 'sendValue') {
if(msg.deviceType == 'humd') {
humdControlData.currentHum = msg.currHum;
humdControlData.currentTemp = msg.currTemp;
controlHumd();
}
else if(msg.deviceType == 'sleepSensor') {
handleSleepData(msg.deviceID, msg.value);
}
}
};
const broadCastMessage = (message) => {
aWss.clients.forEach(function (client) {
client.send(message);
});
}
service.register("startServer", function(message) {
console.log('WebSocketServer on?');
app.listen(port);
console.log('WebSocketServer on!');
// heartbeat 구독
const sub = service.subscribe(`luna://${pkgInfo.name}/heartbeat`, {subscribe:true});
// const max = 120;
// let count = 0;
sub.addListener("response", function(msg) {
console.log(JSON.stringify(msg.payload));
// if (++count >= max) {
// sub.cancel();
// setTimeout(function(){
// // console.log(max+" responses recieved, exiting...");
// process.exit(0);
// }, 1000);
// }
});
message.respond({
returnValue: true,
Response: "Start Server!"
});
});
// ***************************** Heartbeat *****************************
// send responses to each subscribed client
function sendResponses() {
// console.log(logHeader, "send_response");
// console.log("Sending responses, subscription count=" + Object.keys(subscriptions).length);
for (const i in subscriptions) {
if (Object.prototype.hasOwnProperty.call(subscriptions, i)) {
const s = subscriptions[i];
s.respond({
returnValue: true,
event: "beat " + x
});
}
}
x++;
}
// handle subscription requests
const subscriptions = {};
let interval;
let x = 1;
function createInterval() {
if (interval) {
return;
}
console.log(logHeader, "create_interval");
console.log("create new interval");
interval = setInterval(function() {
sendResponses();
}, 1000);
}
// ***************************** Create Toast *****************************
function createToast(message) {
service.call("luna://com.webos.notification/createToast", {message:message}, function(m2) {
console.log(logHeader, "SERVICE_METHOD_CALLED:com.webos.notification/createToast");
});
}
const heartbeat2 = service.register("heartbeat");
heartbeat2.on("request", function(message) {
console.log(logHeader, "SERVICE_METHOD_CALLED:/heartbeat/request");
console.log("heartbeat callback");
message.respond({event: "beat"});
if (message.isSubscription) {
subscriptions[message.uniqueToken] = message;
if (!interval) {
createInterval();
}
}
});
heartbeat2.on("cancel", function(message) {
console.log(logHeader, "SERVICE_METHOD_CALLED:/heartbeat/cancel");
console.log("Canceled " + message.uniqueToken);
delete subscriptions[message.uniqueToken];
const keys = Object.keys(subscriptions);
if (keys.length === 0) {
console.log("no more subscriptions, canceling interval");
clearInterval(interval);
interval = undefined;
}
});
// **********************************************************************
let ledStates = {
'LED01' : false,
'LED02' : false,
'LED03' : false,
'LED04' : false,
'LED05' : false,
};
service.register('getLedStates', function(message){
message.respond({
returnValue : true,
data : ledStates
});
});
service.register('setLedState', function(message){
let deviceID = message.payload.deviceID;
ledStates[deviceID] = message.payload.value;
console.log('setLedState', ledStates);
let statusString = ledStates[deviceID] ? "on" : "off";
let command = {
msgType : "command",
deviceType : "led",
deviceID : deviceID,
status : statusString
};
broadCastMessage(JSON.stringify(command));
message.respond({
returnValue : true,
});
});
'webOS 프로젝트' 카테고리의 다른 글
webOS를 활용한 HomeIoT : 스마트 가습기2 - Enact App (0) | 2021.11.27 |
---|---|
webOS를 활용한 HomeIoT : 스마트 가습기1 - 디바이스 (0) | 2021.11.27 |
webOS를 활용한 HomeIoT : 조명제어2 - Enact App (0) | 2021.11.27 |
webOS를 활용한 HomeIoT : 조명제어1 - 디바이스 (0) | 2021.11.27 |
webOS를 활용한 HomeIoT : 전체 시스템 소개 (0) | 2021.11.27 |