icu-connect
Version:
connect and run Innovative Technology ICU™ device
360 lines (312 loc) • 11.5 kB
JavaScript
const api = require('./api')
const db = require('./dao')
const uuid = require('uuid')
const sleep = ms => new Promise(r => setTimeout(r, ms));
const SM_CONNECT = 0;
const SM_WAIT = 1;
const SM_POLL = 2;
const SM_UPDATE_FACES = 3;
const SM_DETAIL = 4;
const SM_GET_SETTINGS = 5;
const SM_SET_SETTINGS = 6;
const SM_PURGE_FACES = 7;
const SM_TOKEN_REFRESH = 8;
var smState = SM_CONNECT;
var token = "";
var runSM = false;
var LastFaceUpdate = 0;
var enrollData = []
var icuDeviceDetail = {}
var icuDeviceSetting = {}
var enrollRecords = []
const enrollBatchMax = 50
var enrollBatchIndex = 0
var noFaceCount = 0
var faceCount = 0
var readySent = false
var disconnectSent = true
var tokenRefreshTick = 0
const TOKEN_REFRESH_TIME = (60 * 2 * 60 * 1000)/10;
function SetOptions(op)
{
api.setOptions(op)
db.setOptions(op)
}
function NewFaceData(data){
// add data to array
enrollData.push(data)
}
function SetState(main_callback){
// check for token refresh
tokenRefreshTick++;
if(smState == SM_POLL){
if(tokenRefreshTick >= TOKEN_REFRESH_TIME){
smState = SM_TOKEN_REFRESH
tokenRefreshTick = 0;
}
}
// check for any enrollments (any items on array)
if(smState == SM_POLL && enrollData.length > 0){
// get the first array item
var face = enrollData.pop()
// save it to the database. The state-machine will then see a new addition and send it to the ICU
SaveFace(face,function(err,save_data){
if(err){
}else{
var face_save = {
'face_saved':save_data
}
main_callback(face_save)
}
})
}
switch (smState) {
case SM_WAIT:
// do nothing
break;
case SM_CONNECT:
console.log(TOKEN_REFRESH_TIME)
tokenRefreshTick = 0
if(!disconnectSent){
var c_data = {
'device_connected':false,
}
disconnectSent = true;
main_callback(c_data)
}
readySent = false
api.getToken(function (statusCode, apiresponse) {
if (statusCode == 200) {
token = apiresponse.access_token
smState = SM_DETAIL
} else {
smState = SM_CONNECT
}
});
smState = SM_WAIT;
break;
case SM_TOKEN_REFRESH:
api.getToken(function (statusCode, apiresponse) {
if (statusCode == 200) {
token = apiresponse.access_token
smState = SM_POLL
tokenRefreshTick = 0;
} else {
smState = SM_CONNECT
}
});
smState = SM_WAIT;
break;
case SM_DETAIL:
api.getDeviceDetail(token,function(statusCode,apiresponse){
if(statusCode == 200){
icuDeviceDetail = apiresponse;
var c_data = {
'device_connected':true,
'device_data':icuDeviceDetail
}
main_callback(c_data)
smState = SM_PURGE_FACES
}else{
disconnectSent = false
smState = SM_CONNECT;
}
});
smState = SM_WAIT;
break;
case SM_PURGE_FACES:
main_callback({
'device_state':'initialising'
})
var facedel = {
uid:["all"]
}
api.deleteFaces(token,facedel,function(statusCode,apiresponse){
if(statusCode == 200){
smState = SM_GET_SETTINGS
}else{
disconnectSent = false
smState = SM_CONNECT;
}
});
smState = SM_WAIT;
break;
case SM_GET_SETTINGS:
api.getDeviceSettings(token,function(statusCode,apiresponse){
if(statusCode == 200){
icuDeviceSetting = apiresponse;
smState = SM_SET_SETTINGS
}else{
disconnectSent = false
smState = SM_CONNECT;
}
});
smState = SM_WAIT;
break;
case SM_SET_SETTINGS:
var ab = {
Cameras:[
{
Id_Index:0,
Active_Box:true
}
]
}
api.setDeviceSettings(token,ab,function(statusCode,apiresponse){
if(statusCode == 200){
smState = SM_POLL
}else{
disconnectSent = false;
smState = SM_CONNECT;
}
});
smState = SM_WAIT;
break;
case SM_POLL:
api.poll(token,function(statusCode,apiresponse){
if(statusCode == 200){
if(!readySent && 'DeviceState' in apiresponse && apiresponse['DeviceState'] == 'ready'){
main_callback({
'device_state':'ready'
})
readySent = true
}
parsePoll(apiresponse, function(response,data){
smState = response;
if(smState == SM_UPDATE_FACES){
enrollRecords = data;
enrollBatchIndex = 0;
}else{
if(data){
main_callback(data)
}
}
});
}else{
disconnectSent = false
smState = SM_CONNECT;
}
});
smState = SM_WAIT;
break;
case SM_UPDATE_FACES:
var recEnd = (enrollBatchIndex*enrollBatchMax) + enrollBatchMax
var loopEnd = false;
if(enrollRecords.length <= recEnd){
recEnd = (enrollBatchIndex*enrollBatchMax) + enrollRecords.length - (enrollBatchIndex*enrollBatchMax)
loopEnd = true;
}
var up = []
for(i = (enrollBatchIndex*enrollBatchMax); i < recEnd; i++){
var fc = {
Uid:enrollRecords[i].face_id,
Version:enrollRecords[i].face_version,
Data:enrollRecords[i].face_data,
Group:enrollRecords[i].user_group,
GroupId:enrollRecords[i].group_id
}
up.push(fc)
}
var face_data = {
last_update_time:LastFaceUpdate,
updates:up
}
api.updateFaces(token,face_data,function(status,result){
if(loopEnd){
smState = SM_POLL
}else{
enrollBatchIndex += 1
smState = SM_UPDATE_FACES
}
});
smState = SM_WAIT
break;
}
}
function parsePoll(apiresponse, callback)
{
var data = null
if(('FaceInFrame' in apiresponse && apiresponse.FaceInFrame[0].Face) ||
(apiresponse.Detections !== null && apiresponse.Detections.length > 0) ){
noFaceCount = 0
faceCount++
if(faceCount >= 0 && apiresponse.Detections.length > 0){
data = {
age:apiresponse.Detections[0].Age,
uid:apiresponse.Detections[0].Uid,
image:apiresponse.Detections[0].Image
}
data['session'] = true
if(data.uid != 'none'){
db.getRecordById(data.uid,function(error,result){
if(error){
data['record_image'] = ''
}
if(result && result.length == 1){
data['record_image'] = result[0].face_image
}else{
data['record_image'] = ''
}
});
}else{
data['record_image'] = ''
data['feature'] = apiresponse.Detections[0].Feature
}
}else{
data = {
'session':true
}
}
}else{
noFaceCount++
if(noFaceCount >= 3){
data = {
'session':false
}
noFaceCount = 0
faceCount = 0
}
}
db.getUpdates(apiresponse.LastFaceUpdate, function(err,result){
if(!err && result.length){
LastFaceUpdate = result[0].added
callback(SM_UPDATE_FACES,result)
}else{
callback(SM_POLL, data)
}
});
}
function SaveFace(faceData,callback)
{
const buff = Buffer.from(faceData.feature, 'base64');
const val = uuid.v4();
var datesecs = Math.floor(Date.now()/1000)
var face = {
face_id:val,
face_data:buff.toString('utf-8'),
firstname:'',
surname: '',
user_group:'Enrolled',
group_id:0,
face_version:"2.0",
face_image:faceData.image,
added:datesecs
}
db.addFace(face,function(err,result){
if(err){
callback(err,'fail')
}else{
var face_data = {
'uid':face.face_id,
'image':face.face_image,
'timeadded':face.added
}
callback(null,face_data)
}
});
}
module.exports = {
EnrollData:NewFaceData,
SetState:SetState,
SetOptions:SetOptions
}