6 * Class provides AMB related functionality utilizing `navigator.vehicle` API for signals used in HTML applications. This component is usually initialized by {{#crossLink "Bootstrap"}}{{/crossLink}} class
7 * and can be later accessed using {{#crossLink "Bootstrap/carIndicator:property"}}{{/crossLink}} property. Signals recognized by this class needs to be registered in property
8 * {{#crossLink "CarIndicator/_mappingTable:property"}}{{/crossLink}}.
10 * To attach and detach to particular property register new callback object using {{#crossLink "Bootstrap/carIndicator:addListener"}}{{/crossLink}} method, e.g.:
12 * var listenerId = bootstrap.carIndicator.addListener({
13 * onSteeringWheelAngleChanged: function(newValue){
14 * // Process new value
16 * onWheelBrakeChanged : function(newValue){
17 * // Process new value
21 * // Unregister listener
22 * bootstrap.carIndicator.removeListener(listenerId);
24 * Currently following signals are recognized:
26 * * SteeringWheelAngle
27 * * SteeringWheelAngle
42 * * TargetTemperatureRight
43 * * TargetTemperatureLeft
55 * * ExteriorTemperature
57 * * InteriorTemperature
67 * * ExteriorBrightness
69 * * DirectionIndicationINST
70 * * DirectionIndicationMS
76 * * HeatedSeatFRModeRequest
77 * * HeatedSeatFRRequest
78 * * HeatedSeatFLModeRequest
79 * * HeatedSeatFLRequest
86 var CarIndicator = function() {
88 console.info("Starting up service CarIndicator");
91 if (typeof Zone !== 'function')
93 window.Zone = function(){return undefined;};
96 function parseInteger(value) {
98 return parseInt(value, 10);
101 function kmhToMph(value) {
103 var kmh = parseInteger(value);
104 return Math.round(kmh * 0.621371);
107 function parseTirePressure(value) {
109 var floatValue = parseFloat(value).toFixed(2);
110 if (floatValue > 180 && floatValue < 220) {
117 * Array of registered listeners
119 * @property _listeners
122 CarIndicator.prototype._listeners = {};
125 * Array of registered listener IDs.
127 * @property _listenerIDs
130 CarIndicator.prototype._listenerIDs = [];
133 * Signal mapping table.
134 * Each entry should form an object
135 * @property _mappingTable
139 CarIndicator.prototype._mappingTable = {
143 ZONE_Middle = 000010;
147 ZONE_Center = 100000;
149 /* this is for steeringWheel game controler */
150 "SteeringWheelAngle" : {
151 attributeName : "steeringWheelAngle",
152 callBackPropertyName : "SteeringWheelAngle",
153 interfaceName : "steeringWheel",
154 conversionFunction : function(value) {
156 value = parseInt(value, 10);
158 if (value <= 180 && value > 0) {
159 returnValue = (1 * (value / 6)) - 30;
160 } else if (value <= 360 && value > 180) {
161 returnValue = ((value - 179) / 6);
162 } else if (value === 0) {
169 attributeName : "engaged",
170 callBackPropertyName : "WheelBrake",
171 interfaceName : "brakeOperation"
173 /* end steeringWheel game controler*/
174 "TirePressureLeftFront" : {
175 attributeName : "pressure",
176 callBackPropertyName : "tirePressureLeftFront",
177 interfaceName : "tire",
178 conversionFunction : parseTirePressure
179 //zone : new Zone(["Front","Left"])
181 "TirePressureRightFront" : {
182 attributeName : "pressure",
183 callBackPropertyName : "tirePressureRightFront",
184 interfaceName : "tire",
185 conversionFunction : parseTirePressure
186 //zone : new Zone(["Front","Right"])
188 "TirePressureLeftRear" : {
189 attributeName : "pressure",
190 callBackPropertyName : "tirePressureLeftRear",
191 interfaceName : "tire",
192 conversionFunction : parseTirePressure
193 //zone : new Zone(["Rear","Left"])
195 "TirePressureRightRear" : {
196 attributeName : "pressure",
197 callBackPropertyName : "tirePressureRightRear",
198 interfaceName : "tire",
199 conversionFunction : parseTirePressure
200 //zone : new Zone(["Rear","Right"])
203 attributeName : "lock",
204 callBackPropertyName : "childLock",
205 interfaceName : "childSafetyLock"
208 attributeName : "defrostWindow",
209 callBackPropertyName : "frontDefrost",
210 interfaceName : "defrost",
211 zone : new Zone(["front"])
214 attributeName : "defrostWindow",
215 callBackPropertyName : "rearDefrost",
216 interfaceName : "defrost",
217 zone : new Zone(["rear"])
220 attributeName : "fanSpeedLevel",
221 callBackPropertyName : "fanSpeed",
222 interfaceName : "climateControl",
223 conversionFunction : parseInteger
225 "TargetTemperatureRight" : {
226 attributeName : "targetTemperature",
227 callBackPropertyName : "targetTemperatureRight",
228 interfaceName : "climateControl",
229 conversionFunction : parseInteger,
230 zone : new Zone(["front", "right"])
232 "TargetTemperatureLeft" : {
233 attributeName : "targetTemperature",
234 callBackPropertyName : "targetTemperatureLeft",
235 interfaceName : "climateControl",
236 conversionFunction : parseInteger,
237 zone : new Zone(["front", "left"])
240 attributeName : "hazard",
241 callBackPropertyName : "hazard",
242 interfaceName : "lightStatus"
245 attributeName : "head",
246 callBackPropertyName : "frontLights",
247 interfaceName : "lightStatus"
249 "SeatHeaterRight" : {
250 attributeName : "seatHeater",
251 callBackPropertyName : "seatHeaterRight",
252 interfaceName : "climateControl",
253 zone : new Zone(["front", "right"])
256 attributeName : "seatHeater",
257 callBackPropertyName : "seatHeaterLeft",
258 interfaceName : "climateControl",
259 zone : new Zone(["front", "left"])
262 attributeName : "parking",
263 callBackPropertyName : "rearLights",
264 interfaceName : "lightStatus",
266 "AirConditioning" : {
267 attributeName : "airConditioning",
268 callBackPropertyName : "fan",
269 interfaceName : "climateControl"
271 "AirRecirculation" : {
272 attributeName : "airRecirculation",
273 callBackPropertyName : "airRecirculation",
274 interfaceName : "climateControl"
276 "AirflowDirection" : {
277 attributeName : "airflowDirectionW3C",
278 callBackPropertyName : "airflowDirection",
279 interfaceName : "climateControl",
280 conversionFunction : parseInteger
283 attributeName : "chargeLevel",
284 callBackPropertyName : "batteryStatus",
285 interfaceName : "batteryStatus",
286 conversionFunction : parseInteger
288 "FullBatteryRange" : {
289 attributeName : "fullBatteryRange",
290 callBackPropertyName : "fullBatteryRange",
291 conversionFunction : parseInteger
294 attributeName : "exteriorTemperature",
295 callBackPropertyName : "outsideTemp",
296 interfaceName : "temperature",
297 conversionFunction : parseInteger
300 attributeName : "interiorTemperature",
301 callBackPropertyName : "insideTemp",
302 interfaceName : "temperature",
303 conversionFunction : parseInteger
306 attributeName : "frontWheelRadius",
307 callBackPropertyName : "wheelAngle",
308 //interfaceName : "wheelConfiguration",
309 conversionFunction : parseInteger
312 attributeName : "weather",
313 callBackPropertyName : "weather",
314 conversionFunction : parseInteger
317 attributeName : "avgKW",
318 callBackPropertyName : "avgKW",
319 //interfaceName : "AvgKW",
320 conversionFunction : function(newValue) {
322 return parseFloat(newValue).toFixed(2);
326 attributeName : "speed",
327 callBackPropertyName : "speed",
328 interfaceName : "vehicleSpeed",
329 conversionFunction : kmhToMph
332 attributeName : "odometer",
333 callBackPropertyName : "odoMeter",
334 interfaceName : "odometer",
335 conversionFunction : parseInteger
337 "TransmissionShiftPosition" : {
338 attributeName : "mode",
339 callBackPropertyName : "gear",
340 conversionFunction : function(value) {
367 interfaceName : "transmission"
370 attributeName : "randomize",
371 callBackPropertyName : "randomize",
372 interfaceName : "Randomize"
374 "ExteriorBrightness" : {
375 attributeName : "exteriorBrightness",
376 callBackPropertyName : "exteriorBrightness"
379 attributeName : "mode",
380 callBackPropertyName : "nightMode",
381 interfaceName : "nightMode"
383 "DirectionIndicationINST" : {
384 attributeName : "DirectionIndicationINST",
385 callBackPropertyName : "DirectionIndicationINST",
386 //interfaceName : "DirectionIndicationINST"
388 "DirectionIndicationMS" : {
389 attributeName : "DirectionIndicationMS",
390 callBackPropertyName : "DirectionIndicationMS",
391 //interfaceName : "DirectionIndicationMS"
394 attributeName : "ACCommand",
395 callBackPropertyName : "ACCommand",
396 //interfaceName : "ACCommand"
399 attributeName : "RecircReq",
400 callBackPropertyName : "RecircReq",
401 //interfaceName : "RecircReq"
403 "FrontTSetRightCmd" : {
404 attributeName : "FrontTSetRightCmd",
405 callBackPropertyName : "FrontTSetRightCmd",
406 //interfaceName : "FrontTSetRightCmd"
408 "FrontTSetLeftCmd" : {
409 attributeName : "FrontTSetLeftCmd",
410 callBackPropertyName : "FrontTSetLeftCmd",
411 //interfaceName : "FrontTSetLeftCmd"
413 "FrontBlwrSpeedCmd" : {
414 attributeName : "FrontBlwrSpeedCmd",
415 callBackPropertyName : "FrontBlwrSpeedCmd",
416 //interfaceName : "FrontBlwrSpeedCmd"
418 "HeatedSeatFRRequest" : {
419 attributeName : "seatHeater",
420 callBackPropertyName : "HeatedSeatFRRequest",
421 interfaceName : "climateControl",
422 zone : new Zone(["front", "right"])
424 "HeatedSeatFLRequest" : {
425 attributeName : "seatHeater",
426 callBackPropertyName : "HeatedSeatFLRequest",
427 interfaceName : "climateControl",
428 zone : new Zone(["front", "left"])
431 attributeName : "FLHSDistrCmd",
432 callBackPropertyName : "FLHSDistrCmd",
433 //interfaceName : "FLHSDistrCmd"
436 attributeName : "FRHSDistrCmd",
437 callBackPropertyName : "FRHSDistrCmd",
438 //interfaceName : "FRHSDistrCmd"
443 * This method adds listener object for car events. Object should define function callbacks taking signal names from mapping table, e.g.:
446 * onBatteryChange: function(newValue, oldValue) {}
448 * Methods are called back with new and last known values.
449 * @method addListener
450 * @param callback {Object} object with callback functions.
451 * @return {Integer} WatchID for later removal of listener.
453 CarIndicator.prototype.addListener = function(aCallbackObject) {
455 var id = Math.floor(Math.random() * 1000000);
457 this._listeners[id] = aCallbackObject;
458 this._listenerIDs.push(id);
460 var subscribeCallback = function(data) {
461 self.onDataUpdate(data, self);
463 for ( var i in aCallbackObject) {
464 if (aCallbackObject.hasOwnProperty(i)) {
465 var prop = i.replace("on", "").replace("Changed", "");
467 for ( var signal in this._mappingTable) {
468 if (this._mappingTable.hasOwnProperty(signal)) {
469 var mapping = this._mappingTable[signal];
470 var zone = mapping.zone;
471 var interfaceName = signal;
473 if (mapping.interfaceName !== "undefined") {
474 interfaceName = mapping.interfaceName;
477 if (mapping.callBackPropertyName.toLowerCase() === prop.toLowerCase() && !mapping.subscribeCount) {
478 mapping.subscribeCount = typeof (mapping.subscribeCount) === "undefined" ? 0 : mapping.subscribeCount++;
479 if (typeof (navigator.vehicle) !== 'undefined') {
480 if (typeof (navigator.vehicle[interfaceName]) !== "undefined") {
481 if (!(interfaceName.toString().trim().toLowerCase() === "nightmode" && id === this._listenerIDs[0])) {
482 if (navigator.vehicle[interfaceName]){
483 var setUpData = navigator.vehicle[interfaceName].get(zone);
484 if (setUpData !== undefined)
485 self.onDataUpdate(setUpData, self, id);
488 if (typeof (navigator.vehicle[interfaceName].subscribe) !== "undefined")
490 console.log("Modello: Subscribing to AMB signal - " + interfaceName);
491 navigator.vehicle[interfaceName].subscribe(subscribeCallback, zone);
494 if (typeof (navigator.vehicle[interfaceName]) === "undefined")
495 console.warn(interfaceName + " is not available to subscribe to");
497 console.warn("Tizen API is not available, cannot subscribe to signal", signal);
500 console.warn("Vehicle API is not available.");
511 * This method is call as callback if data oon navigator.vehicle was change onDataUpdate
512 * @method onDataUpdate
513 * @param data {object} object whit new data.
514 * @param self {object} this carIndicator Object.
515 * @param lisenersID {int} id of listener.
517 CarIndicator.prototype.onDataUpdate = function(data, self, lisenersID) {
519 if (data !== undefined) {
520 if (data.zone !== undefined)
521 var zone = data.zone.toString(2);
526 for ( var property in data) {
527 if (data.hasOwnProperty(property)) {
529 if (property !== "time" && property !== "zone" && property !== "interfaceName" && property.search("Sequence") === -1) {
530 for ( var element in self._mappingTable) {
531 if (self._mappingTable.hasOwnProperty(element) && self._mappingTable[element].interfaceName !== undefined) {
532 if (self._mappingTable[element].interfaceName.toLowerCase() === data.interfaceName.toLowerCase() &&
533 self._mappingTable[element].attributeName.toLowerCase() === property.toLowerCase() &&
534 ((!self._mappingTable[element].zone && (!data.zone || data.zone.value.length === 0)) ||
535 ((self._mappingTable[element].zone && data.zone) &&
536 (typeof(self._mappingTable[element].zone.equals) === typeof(data.zone.equals)) &&
537 self._mappingTable[element].zone.equals(data.zone)))
539 mapping = self._mappingTable[element];
545 if (typeof (mapping) !== 'undefined') {
546 var value = data[property];
547 value = mapping.conversionFunction ? mapping.conversionFunction(value) : value;
549 var oldValue = self.status[mapping.callBackPropertyName];
550 if (oldValue !== value || property.toUpperCase() === "nightMode".toUpperCase()) {
551 console.info("AMB property '" + property + "' has changed to new value:" + value);
552 self.status[mapping.callBackPropertyName] = value;
554 var callbackName = "on" + mapping.callBackPropertyName[0].toUpperCase() + mapping.callBackPropertyName.substring(1) + "Changed";
557 if (lisenersID !== undefined) {
558 listener = self._listeners[lisenersID];
560 if (typeof (listener[callbackName]) === 'function') {
562 listener[callbackName](value, oldValue);
564 console.error("Error occured during executing listener", ex);
568 for ( var i in self._listeners) {
569 if (self._listeners.hasOwnProperty(i)) {
570 listener = self._listeners[i];
572 if (typeof (listener[callbackName]) === 'function') {
574 listener[callbackName](value, oldValue);
576 console.error("Error occured during executing listener", ex);
585 console.warn("Mapping for property '" + property + "' is not defined");
594 * This method removes previosly added listener object. Use WatchID returned from addListener method.
595 * @method removeListener
596 * @param aId {Integer} WatchID.
598 CarIndicator.prototype.removeListener = function(aId) {
600 var listener = this._listeners[aId];
602 for ( var i in listener) {
603 if (listener.hasOwnProperty(i)) {
604 var prop = i.replace("on", "").replace("Changed", "");
606 for ( var signal in this._mappingTable) {
607 if (this._mappingTable.hasOwnProperty(signal)) {
608 var mapping = this._mappingTable[signal];
610 if (mapping.subscribeCount === 0) { // Last signal, unscubscribe
611 if (typeof (navigator.vehicle) !== 'undefined') {
612 navigator.vehicle.unsubscribe(signal);
613 mapping.subscribeCount = undefined;
615 console.warn("Vehicle API is not available.");
617 } else if (typeof (mapping.subscribeCount) !== 'undefined') {
618 mapping.subscribeCount--;
625 this._listeners[aId] = undefined;
634 CarIndicator.prototype.status = {
636 targetTemperatureRight : 0,
637 targetTemperatureLeft : 0,
639 frontDefrost : false,
642 frontRightwhell : "",
651 airRecirculation : false,
652 airflowDirection : 0,
654 fullBatteryRange : 350,
665 exteriorBrightness : 1000
669 * This method return status object in callback
671 * @param callback {function} callback function.
673 CarIndicator.prototype.getStatus = function(callback) {
675 callback(this.status);
679 * this method set status for property in navigator.vehicle and status object
681 * @param indicator {string} indicator name.
682 * @param status {??} ??.
683 * @param text_status {string} new status .
684 * @param callback {function} callback function.
686 CarIndicator.prototype.setStatus = function(indicator, newValue, zone) {
688 var mappingElement, mappingProperty;
689 for ( var element in this._mappingTable) {
690 if (this._mappingTable.hasOwnProperty(element)) {
691 mappingProperty = undefined;
692 if (this._mappingTable[element].callBackPropertyName.toLowerCase() === indicator.toLowerCase()) {
693 mappingElement = this._mappingTable[element];
694 mappingProperty = this._mappingTable[element].attributeName;
700 if (mappingProperty !== undefined) {
701 var objectName = mappingElement.interfaceName;
702 var zoneValue = (mappingElement.zone && mappingElement.zone.value) ? mappingElement.zone.value : undefined;
704 if (typeof (navigator.vehicle) !== 'undefined') {
705 if (typeof (navigator.vehicle[objectName]) !== 'undefined' && typeof (navigator.vehicle[objectName].set) !== 'undefined') {
706 console.log("trying to set: " + objectName + "." + mappingProperty + " in zone " + zoneValue + " to " + newValue);
708 value[mappingProperty] = newValue;
709 navigator.vehicle[objectName].set(value, mappingElement.zone).then(function() {
710 console.log("Set success!");
712 console.log("Set failed! " + error.message);
716 console.error("Can't set status for " + objectName + " because it doesn't exist " + indicator);
719 console.warn("Vehicle API is not available.");