@ -1,8 +1,8 @@
/ *
/ *
Floorplan Fully Kiosk for Home Assistant
Floorplan Fully Kiosk for Home Assistant
Version : 1.0 . 7. 42
Version : 1.0 . 7. 50
By Petar Kozul
By Petar Kozul
https : //github.com/pkozul/ha-floorplan
https : //github.com/pkozul/ha-floorplan
* /
* /
'use strict' ;
'use strict' ;
@ -14,14 +14,16 @@
class FullyKiosk {
class FullyKiosk {
constructor ( floorplan ) {
constructor ( floorplan ) {
this . version = '1.0.7. 42 ';
this . version = '1.0.7. 50 ';
this . floorplan = floorplan ;
this . floorplan = floorplan ;
this . authToken = ( window . localStorage && window . localStorage . authToken ) ? window . localStorage . authToken : '' ;
this . authToken = ( window . localStorage && window . localStorage . authToken ) ? window . localStorage . authToken : '' ;
this . fullyInfo = { } ;
this . fullyInfo = { } ;
this . fullyState = { } ;
this . fullyState = { } ;
this . iBeacons = { } ;
this . beacons = { } ;
this . throttledFunctions = { } ;
}
}
/***************************************************************************************************************************/
/***************************************************************************************************************************/
@ -31,6 +33,13 @@
init ( ) {
init ( ) {
this . logInfo ( 'VERSION' , ` Fully Kiosk v ${ this . version } ` ) ;
this . logInfo ( 'VERSION' , ` Fully Kiosk v ${ this . version } ` ) ;
/ *
let uuid = 'a445425b-c718-461c-a876-aa647abd99d4' ;
let deviceId = uuid . replace ( /[-_]/g , '' ) . toUpperCase ( ) ;
let payload = { room : 'entry hall' , id : uuid , distance : 123.45 } ;
this . PostToHomeAssistant ( ` /api/room_presence/ ${ deviceId } ` , payload ) ;
* /
if ( typeof fully === "undefined" ) {
if ( typeof fully === "undefined" ) {
this . logInfo ( 'FULLY_KIOSK' , ` Fully Kiosk is not running or not enabled. You can enable it via Settings > Other Settings > Enable Website Integration (PLUS). ` ) ;
this . logInfo ( 'FULLY_KIOSK' , ` Fully Kiosk is not running or not enabled. You can enable it via Settings > Other Settings > Enable Website Integration (PLUS). ` ) ;
return ;
return ;
@ -76,6 +85,8 @@
screensaverLightEntityId : device . screensaver _light ,
screensaverLightEntityId : device . screensaver _light ,
mediaPlayerEntityId : device . media _player ,
mediaPlayerEntityId : device . media _player ,
locationName : device . presence _detection ? device . presence _detection . location _name : undefined ,
startUrl : fully . getStartUrl ( ) ,
startUrl : fully . getStartUrl ( ) ,
currentLocale : fully . getCurrentLocale ( ) ,
currentLocale : fully . getCurrentLocale ( ) ,
ipAddressv4 : fully . getIp4Address ( ) ,
ipAddressv4 : fully . getIp4Address ( ) ,
@ -134,8 +145,15 @@
window . addEventListener ( 'fully.onScreensaverStop' , this . onScreensaverStop . bind ( this ) ) ;
window . addEventListener ( 'fully.onScreensaverStop' , this . onScreensaverStop . bind ( this ) ) ;
window . addEventListener ( 'fully.onBatteryLevelChanged' , this . onBatteryLevelChanged . bind ( this ) ) ;
window . addEventListener ( 'fully.onBatteryLevelChanged' , this . onBatteryLevelChanged . bind ( this ) ) ;
window . addEventListener ( 'fully.onMotion' , this . onMotion . bind ( this ) ) ;
window . addEventListener ( 'fully.onMotion' , this . onMotion . bind ( this ) ) ;
window . addEventListener ( 'fully.onMovement' , this . onMovement . bind ( this ) ) ;
window . addEventListener ( 'fully.onIBeacon' , this . onIBeacon . bind ( this ) ) ;
if ( this . fullyInfo . supportsGeolocation ) {
window . addEventListener ( 'fully.onMovement' , this . onMovement . bind ( this ) ) ;
}
if ( this . fullyInfo . locationName ) {
this . logInfo ( 'KIOSK' , 'Listening for beacon messages' ) ;
window . addEventListener ( 'fully.onIBeacon' , this . onIBeacon . bind ( this ) ) ;
}
fully . bind ( 'screenOn' , 'onFullyEvent("fully.screenOn");' )
fully . bind ( 'screenOn' , 'onFullyEvent("fully.screenOn");' )
fully . bind ( 'screenOff' , 'onFullyEvent("fully.screenOff");' )
fully . bind ( 'screenOff' , 'onFullyEvent("fully.screenOff");' )
@ -221,8 +239,19 @@
this . sendMotionState ( ) ;
this . sendMotionState ( ) ;
}
}
onMovement ( ) {
onMovement ( e ) {
this . logDebug ( 'FULLY_KIOSK' , 'Movement detected' ) ;
let functionId = 'onMovement' ;
let throttledFunc = this . throttledFunctions [ functionId ] ;
if ( ! throttledFunc ) {
throttledFunc = this . throttle ( this . onMovementThrottled . bind ( this ) , 10000 ) ;
this . throttledFunctions [ functionId ] = throttledFunc ;
}
return throttledFunc ( e ) ;
}
onMovementThrottled ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Movement detected (throttled)' ) ;
if ( this . fullyInfo . supportsGeolocation ) {
if ( this . fullyInfo . supportsGeolocation ) {
this . updateCurrentPosition ( )
this . updateCurrentPosition ( )
@ -233,19 +262,28 @@
}
}
onIBeacon ( e ) {
onIBeacon ( e ) {
let iBeacon = e . detail ;
let functionId = e . detail . uuid ;
let throttledFunc = this . throttledFunctions [ functionId ] ;
if ( ! throttledFunc ) {
throttledFunc = this . throttle ( this . onIBeaconThrottled . bind ( this ) , 10000 ) ;
this . throttledFunctions [ functionId ] = throttledFunc ;
}
return throttledFunc ( e ) ;
}
this . logDebug ( 'FULLY_KIOSK' , ` iBeacon ( ${ JSON . stringify ( iBeacon ) } ) ` ) ;
onIBeaconThrottled ( e ) {
let beacon = e . detail ;
let iBeaconId = iBeacon . uuid ;
this . logDebug ( 'FULLY_KIOSK' , ` Received (throttled) beacon message ( ${ JSON . stringify ( beacon ) } ) ` ) ;
iBeaconId += ( iBeacon . major ? ` _ ${ iBeacon . major } ` : '' ) ;
iBeaconId += ( iBeacon . minor ? ` _ ${ iBeacon . minor } ` : '' ) ;
this . iBeacons [ iBeaconId ] = iBeacon ;
let beaconId = beacon . uuid ;
beaconId += ( beacon . major ? ` _ ${ beacon . major } ` : '' ) ;
beaconId += ( beacon . minor ? ` _ ${ beacon . minor } ` : '' ) ;
this . sendMotionState ( ) ;
this . beacons[ beaconId ] = beacon ;
this . send IBeaconState( iB eacon) ;
this . send BeaconState( b eacon) ;
}
}
/***************************************************************************************************************************/
/***************************************************************************************************************************/
@ -329,30 +367,61 @@
this . PostToHomeAssistant ( ` /api/fully_kiosk/media_player/ ${ this . fullyInfo . mediaPlayerEntityId } ` , this . newPayload ( state ) ) ;
this . PostToHomeAssistant ( ` /api/fully_kiosk/media_player/ ${ this . fullyInfo . mediaPlayerEntityId } ` , this . newPayload ( state ) ) ;
}
}
send IBeaconState( iB eacon) {
send BeaconState( b eacon) {
if ( ! this . fullyInfo . motionBinarySensorEntityId ) {
if ( ! this . fullyInfo . motionBinarySensorEntityId ) {
return ;
return ;
}
}
/ *
let payload = {
name : this . fullyInfo . locationName ,
address : this . fullyInfo . macAddress ,
device : beacon . uuid ,
beaconUUID : beacon . uuid ,
latitude : this . position ? this . position . coords . latitude : undefined ,
longitude : this . position ? this . position . coords . longitude : undefined ,
entry : 1 ,
}
this . PostToHomeAssistant ( ` /api/geofency ` , payload , undefined , false ) ;
* /
/ *
let payload = {
let payload = {
mac : undefined ,
mac : undefined ,
dev _id : iBeacon . uuid . replace ( /-/g , '_' ) ,
dev _id : b eacon. uuid . replace ( /-/g , '_' ) ,
host _name : undefined ,
host _name : undefined ,
location _name : this . fullyInfo . macAddress ,
location _name : this . fullyInfo . macAddress ,
gps : this . position ? [ this . position . coords . latitude , this . position . coords . longitude ] : undefined ,
gps : this . position ? [ this . position . coords . latitude , this . position . coords . longitude ] : undefined ,
gps _accuracy : undefined ,
gps _accuracy : undefined ,
battery : undefined ,
battery : undefined ,
uuid : iBeacon . uuid ,
uuid : b eacon. uuid ,
major : iBeacon . major ,
major : b eacon. major ,
minor : iBeacon . minor ,
minor : b eacon. minor ,
} ;
} ;
//this.PostToHomeAssistant(`/api/services/device_tracker/see`, payload);
this . PostToHomeAssistant ( ` /api/services/device_tracker/see ` , payload ) ;
* /
/ *
let fullyId = this . fullyInfo . macAddress . replace ( /[:-]/g , "_" ) ;
let fullyId = this . fullyInfo . macAddress . replace ( /[:-]/g , "_" ) ;
payload = { topic : ` room_presence/ ${ fullyId } ` , payload : ` { \" id \" : \" ${ iB eacon. uuid } \" , \" distance \" : ${ iB eacon. distance } } ` } ;
payload = { topic : ` room_presence/ ${ fullyId } ` , payload : ` { \" id \" : \" ${ b eacon. uuid } \" , \" distance \" : ${ b eacon. distance } } ` } ;
this . floorplan . hass . callService ( 'mqtt' , 'publish' , payload ) ;
this . floorplan . hass . callService ( 'mqtt' , 'publish' , payload ) ;
* /
let deviceId = beacon . uuid . replace ( /[-_]/g , '' ) . toUpperCase ( ) ;
let payload = {
room : this . fullyInfo . locationName ,
uuid : beacon . uuid ,
major : beacon . major ,
minor : beacon . minor ,
distance : beacon . distance ,
latitude : this . position ? this . position . coords . latitude : undefined ,
longitude : this . position ? this . position . coords . longitude : undefined ,
} ;
this . PostToHomeAssistant ( ` /api/room_presence/ ${ deviceId } ` , payload ) ;
}
}
newPayload ( state ) {
newPayload ( state ) {
@ -376,7 +445,7 @@
_isScreensaverOn : this . fullyState . isScreensaverOn ,
_isScreensaverOn : this . fullyState . isScreensaverOn ,
_latitude : this . position && this . position . coords . latitude ,
_latitude : this . position && this . position . coords . latitude ,
_longitude : this . position && this . position . coords . longitude ,
_longitude : this . position && this . position . coords . longitude ,
_ iB eacons: JSON . stringify ( Object . keys ( this . iBeacons) . map ( iBeaconId => this . iBeacons [ iB eaconId] ) ) ,
_ b eacons: JSON . stringify ( Object . keys ( this . beacons) . map ( beaconId => this . beacons [ b eaconId] ) ) ,
}
}
} ;
} ;
@ -568,22 +637,152 @@
/ * U t i l i t y f u n c t i o n s
/ * U t i l i t y f u n c t i o n s
/***************************************************************************************************************************/
/***************************************************************************************************************************/
debounce ( func , wait , immediate ) {
debounce ( func , wait , options ) {
let timeout ;
let lastArgs ,
return function ( ) {
lastThis ,
let context = this , args = arguments ;
maxWait ,
result ,
timerId ,
lastCallTime
let lastInvokeTime = 0
let leading = false
let maxing = false
let trailing = true
if ( typeof func != 'function' ) {
throw new TypeError ( 'Expected a function' )
}
wait = + wait || 0
if ( options ) {
leading = ! ! options . leading
maxing = 'maxWait' in options
maxWait = maxing ? Math . max ( + options . maxWait || 0 , wait ) : maxWait
trailing = 'trailing' in options ? ! ! options . trailing : trailing
}
let later = function ( ) {
function invokeFunc ( time ) {
timeout = null ;
const args = lastArgs
if ( ! immediate ) func . apply ( context , args ) ;
const thisArg = lastThis
} ;
let callNow = immediate && ! timeout ;
lastArgs = lastThis = undefined
clearTimeout ( timeout ) ;
lastInvokeTime = time
timeout = setTimeout ( later , wait ) ;
result = func . apply ( thisArg , args )
return result
}
if ( callNow ) func . apply ( context , args ) ;
function leadingEdge ( time ) {
} ;
// Reset any `maxWait` timer.
lastInvokeTime = time
// Start the timer for the trailing edge.
timerId = setTimeout ( timerExpired , wait )
// Invoke the leading edge.
return leading ? invokeFunc ( time ) : result
}
function remainingWait ( time ) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
const timeWaiting = wait - timeSinceLastCall
return maxing
? Math . min ( timeWaiting , maxWait - timeSinceLastInvoke )
: timeWaiting
}
function shouldInvoke ( time ) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return ( lastCallTime === undefined || ( timeSinceLastCall >= wait ) ||
( timeSinceLastCall < 0 ) || ( maxing && timeSinceLastInvoke >= maxWait ) )
}
function timerExpired ( ) {
const time = Date . now ( )
if ( shouldInvoke ( time ) ) {
return trailingEdge ( time )
}
// Restart the timer.
timerId = setTimeout ( timerExpired , remainingWait ( time ) )
}
function trailingEdge ( time ) {
timerId = undefined
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if ( trailing && lastArgs ) {
return invokeFunc ( time )
}
lastArgs = lastThis = undefined
return result
}
function cancel ( ) {
if ( timerId !== undefined ) {
clearTimeout ( timerId )
}
lastInvokeTime = 0
lastArgs = lastCallTime = lastThis = timerId = undefined
}
function flush ( ) {
return timerId === undefined ? result : trailingEdge ( Date . now ( ) )
}
function pending ( ) {
return timerId !== undefined
}
function debounced ( ... args ) {
const time = Date . now ( )
const isInvoking = shouldInvoke ( time )
lastArgs = args
lastThis = this
lastCallTime = time
if ( isInvoking ) {
if ( timerId === undefined ) {
return leadingEdge ( lastCallTime )
}
if ( maxing ) {
// Handle invocations in a tight loop.
timerId = setTimeout ( timerExpired , wait )
return invokeFunc ( lastCallTime )
}
}
if ( timerId === undefined ) {
timerId = setTimeout ( timerExpired , wait )
}
return result
}
debounced . cancel = cancel
debounced . flush = flush
debounced . pending = pending
return debounced
}
throttle ( func , wait , options ) {
let leading = true
let trailing = true
if ( typeof func != 'function' ) {
throw new TypeError ( 'Expected a function' ) ;
}
if ( options ) {
leading = 'leading' in options ? ! ! options . leading : leading
trailing = 'trailing' in options ? ! ! options . trailing : trailing
}
return this . debounce ( func , wait , {
'leading' : leading ,
'maxWait' : wait ,
'trailing' : trailing
} )
}
}
}
}