<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

/* More information about these options at jshint.com/docs/options */
/* jshint browser: true, camelcase: true, curly: true, devel: true,
   eqeqeq: true, forin: false, globalstrict: true, node: true,
   quotmark: single, undef: true, unused: strict */
/* global mozRTCIceCandidate, mozRTCPeerConnection, Promise,
mozRTCSessionDescription, webkitRTCPeerConnection, MediaStreamTrack */
/* exported trace,requestUserMedia */
'use strict';

var RTCPeerConnection = null;
var getUserMedia = null;
var attachMediaStream = null;
var reattachMediaStream = null;
var webrtcDetectedBrowser = null;
var webrtcDetectedVersion = null;

function trace(text) {
  // This function is used for logging.
  if (text[text.length - 1] === '\n') {
    text = text.substring(0, text.length - 1);
  }
  if (window.performance) {
    var now = (window.performance.now() / 1000).toFixed(3);
    console.log(now + ': ' + text);
  } else {
    console.log(text);
  }
}

if (navigator.mozGetUserMedia) {
  console.log('This appears to be Firefox');

  webrtcDetectedBrowser = 'firefox';

  webrtcDetectedVersion =
    parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);

  // The RTCPeerConnection object.
  RTCPeerConnection = function(pcConfig, pcConstraints) {
    // .urls is not supported in FF yet.
    if (pcConfig && pcConfig.iceServers) {
      for (var i = 0; i < pcConfig.iceServers.length; i++) {
        if (pcConfig.iceServers[i].hasOwnProperty('urls')) {
          pcConfig.iceServers[i].url = pcConfig.iceServers[i].urls;
          delete pcConfig.iceServers[i].urls;
        }
      }
    }
    return new mozRTCPeerConnection(pcConfig, pcConstraints);
  };

  // The RTCSessionDescription object.
  window.RTCSessionDescription = mozRTCSessionDescription;

  // The RTCIceCandidate object.
  window.RTCIceCandidate = mozRTCIceCandidate;

  // getUserMedia shim (only difference is the prefix).
  // Code from Adam Barth.
  getUserMedia = navigator.mozGetUserMedia.bind(navigator);
  navigator.getUserMedia = getUserMedia;

  // Shim for MediaStreamTrack.getSources.
  MediaStreamTrack.getSources = function(successCb) {
    setTimeout(function() {
      var infos = [
        {kind: 'audio', id: 'default', label:'', facing:''},
        {kind: 'video', id: 'default', label:'', facing:''}
      ];
      successCb(infos);
    }, 0);
  };

  // Creates ICE server from the URL for FF.
  window.createIceServer = function(url, username, password) {
    var iceServer = null;
    var urlParts = url.split(':');
    if (urlParts[0].indexOf('stun') === 0) {
      // Create ICE server with STUN URL.
      iceServer = {
        'url': url
      };
    } else if (urlParts[0].indexOf('turn') === 0) {
      if (webrtcDetectedVersion < 27) {
        // Create iceServer with turn url.
        // Ignore the transport parameter from TURN url for FF version <=27.
        var turnUrlParts = url.split('?');
        // Return null for createIceServer if transport=tcp.
        if (turnUrlParts.length === 1 ||
          turnUrlParts[1].indexOf('transport=udp') === 0) {
          iceServer = {
            'url': turnUrlParts[0],
            'credential': password,
            'username': username
          };
        }
      } else {
        // FF 27 and above supports transport parameters in TURN url,
        // So passing in the full url to create iceServer.
        iceServer = {
          'url': url,
          'credential': password,
          'username': username
        };
      }
    }
    return iceServer;
  };

  window.createIceServers = function(urls, username, password) {
    var iceServers = [];
    // Use .url for FireFox.
    for (var i = 0; i < urls.length; i++) {
      var iceServer =
        window.createIceServer(urls[i], username, password);
      if (iceServer !== null) {
        iceServers.push(iceServer);
      }
    }
    return iceServers;
  };

  // Attach a media stream to an element.
  attachMediaStream = function(element, stream) {
    console.log('Attaching media stream');
    element.mozSrcObject = stream;
  };

  reattachMediaStream = function(to, from) {
    console.log('Reattaching media stream');
    to.mozSrcObject = from.mozSrcObject;
  };

} else if (navigator.webkitGetUserMedia) {
  console.log('This appears to be Chrome');

  webrtcDetectedBrowser = 'chrome';
  // Temporary fix until crbug/374263 is fixed.
  // Setting Chrome version to 999, if version is unavailable.
  var result = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
  if (result !== null) {
    webrtcDetectedVersion = parseInt(result[2], 10);
  } else {
    webrtcDetectedVersion = 999;
  }

  // Creates iceServer from the url for Chrome M33 and earlier.
  window.createIceServer = function(url, username, password) {
    var iceServer = null;
    var urlParts = url.split(':');
    if (urlParts[0].indexOf('stun') === 0) {
      // Create iceServer with stun url.
      iceServer = {
        'url': url
      };
    } else if (urlParts[0].indexOf('turn') === 0) {
      // Chrome M28 & above uses below TURN format.
      iceServer = {
        'url': url,
        'credential': password,
        'username': username
      };
    }
    return iceServer;
  };

  // Creates an ICEServer object from multiple URLs.
  window.createIceServers = function(urls, username, password) {
    return {
      'urls': urls,
      'credential': password,
      'username': username
    };
  };

  // The RTCPeerConnection object.
  RTCPeerConnection = function(pcConfig, pcConstraints) {
    return new webkitRTCPeerConnection(pcConfig, pcConstraints);
  };

  // Get UserMedia (only difference is the prefix).
  // Code from Adam Barth.
  getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
  navigator.getUserMedia = getUserMedia;

  // Attach a media stream to an element.
  attachMediaStream = function(element, stream) {
    if (typeof element.srcObject !== 'undefined') {
      element.srcObject = stream;
    } else if (typeof element.mozSrcObject !== 'undefined') {
      element.mozSrcObject = stream;
    } else if (typeof element.src !== 'undefined') {
      element.src = URL.createObjectURL(stream);
    } else {
      console.log('Error attaching stream to element.');
    }
  };

  reattachMediaStream = function(to, from) {
    to.src = from.src;
  };
} else {
  console.log('Browser does not appear to be WebRTC-capable');
}

// Returns the result of getUserMedia as a Promise.
function requestUserMedia(constraints) {
  return new Promise(function(resolve, reject) {
    var onSuccess = function(stream) {
      resolve(stream);
    };
    var onError = function(error) {
      reject(error);
    };

    try {
      getUserMedia(constraints, onSuccess, onError);
    } catch (e) {
      reject(e);
    }
  });
}

if (typeof module !== 'undefined') {
  module.exports = {
    RTCPeerConnection: RTCPeerConnection,
    getUserMedia: getUserMedia,
    attachMediaStream: attachMediaStream,
    reattachMediaStream: reattachMediaStream,
    webrtcDetectedBrowser: webrtcDetectedBrowser,
    webrtcDetectedVersion: webrtcDetectedVersion
    //requestUserMedia: not exposed on purpose.
    //trace: not exposed on purpose.
  };
}
<commit_msg>Use resolve and reject as onSuccess and onError<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

/* More information about these options at jshint.com/docs/options */
/* jshint browser: true, camelcase: true, curly: true, devel: true,
   eqeqeq: true, forin: false, globalstrict: true, node: true,
   quotmark: single, undef: true, unused: strict */
/* global mozRTCIceCandidate, mozRTCPeerConnection, Promise,
mozRTCSessionDescription, webkitRTCPeerConnection, MediaStreamTrack */
/* exported trace,requestUserMedia */
'use strict';

var RTCPeerConnection = null;
var getUserMedia = null;
var attachMediaStream = null;
var reattachMediaStream = null;
var webrtcDetectedBrowser = null;
var webrtcDetectedVersion = null;

function trace(text) {
  // This function is used for logging.
  if (text[text.length - 1] === '\n') {
    text = text.substring(0, text.length - 1);
  }
  if (window.performance) {
    var now = (window.performance.now() / 1000).toFixed(3);
    console.log(now + ': ' + text);
  } else {
    console.log(text);
  }
}

if (navigator.mozGetUserMedia) {
  console.log('This appears to be Firefox');

  webrtcDetectedBrowser = 'firefox';

  webrtcDetectedVersion =
    parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);

  // The RTCPeerConnection object.
  RTCPeerConnection = function(pcConfig, pcConstraints) {
    // .urls is not supported in FF yet.
    if (pcConfig && pcConfig.iceServers) {
      for (var i = 0; i < pcConfig.iceServers.length; i++) {
        if (pcConfig.iceServers[i].hasOwnProperty('urls')) {
          pcConfig.iceServers[i].url = pcConfig.iceServers[i].urls;
          delete pcConfig.iceServers[i].urls;
        }
      }
    }
    return new mozRTCPeerConnection(pcConfig, pcConstraints);
  };

  // The RTCSessionDescription object.
  window.RTCSessionDescription = mozRTCSessionDescription;

  // The RTCIceCandidate object.
  window.RTCIceCandidate = mozRTCIceCandidate;

  // getUserMedia shim (only difference is the prefix).
  // Code from Adam Barth.
  getUserMedia = navigator.mozGetUserMedia.bind(navigator);
  navigator.getUserMedia = getUserMedia;

  // Shim for MediaStreamTrack.getSources.
  MediaStreamTrack.getSources = function(successCb) {
    setTimeout(function() {
      var infos = [
        {kind: 'audio', id: 'default', label:'', facing:''},
        {kind: 'video', id: 'default', label:'', facing:''}
      ];
      successCb(infos);
    }, 0);
  };

  // Creates ICE server from the URL for FF.
  window.createIceServer = function(url, username, password) {
    var iceServer = null;
    var urlParts = url.split(':');
    if (urlParts[0].indexOf('stun') === 0) {
      // Create ICE server with STUN URL.
      iceServer = {
        'url': url
      };
    } else if (urlParts[0].indexOf('turn') === 0) {
      if (webrtcDetectedVersion < 27) {
        // Create iceServer with turn url.
        // Ignore the transport parameter from TURN url for FF version <=27.
        var turnUrlParts = url.split('?');
        // Return null for createIceServer if transport=tcp.
        if (turnUrlParts.length === 1 ||
          turnUrlParts[1].indexOf('transport=udp') === 0) {
          iceServer = {
            'url': turnUrlParts[0],
            'credential': password,
            'username': username
          };
        }
      } else {
        // FF 27 and above supports transport parameters in TURN url,
        // So passing in the full url to create iceServer.
        iceServer = {
          'url': url,
          'credential': password,
          'username': username
        };
      }
    }
    return iceServer;
  };

  window.createIceServers = function(urls, username, password) {
    var iceServers = [];
    // Use .url for FireFox.
    for (var i = 0; i < urls.length; i++) {
      var iceServer =
        window.createIceServer(urls[i], username, password);
      if (iceServer !== null) {
        iceServers.push(iceServer);
      }
    }
    return iceServers;
  };

  // Attach a media stream to an element.
  attachMediaStream = function(element, stream) {
    console.log('Attaching media stream');
    element.mozSrcObject = stream;
  };

  reattachMediaStream = function(to, from) {
    console.log('Reattaching media stream');
    to.mozSrcObject = from.mozSrcObject;
  };

} else if (navigator.webkitGetUserMedia) {
  console.log('This appears to be Chrome');

  webrtcDetectedBrowser = 'chrome';
  // Temporary fix until crbug/374263 is fixed.
  // Setting Chrome version to 999, if version is unavailable.
  var result = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
  if (result !== null) {
    webrtcDetectedVersion = parseInt(result[2], 10);
  } else {
    webrtcDetectedVersion = 999;
  }

  // Creates iceServer from the url for Chrome M33 and earlier.
  window.createIceServer = function(url, username, password) {
    var iceServer = null;
    var urlParts = url.split(':');
    if (urlParts[0].indexOf('stun') === 0) {
      // Create iceServer with stun url.
      iceServer = {
        'url': url
      };
    } else if (urlParts[0].indexOf('turn') === 0) {
      // Chrome M28 & above uses below TURN format.
      iceServer = {
        'url': url,
        'credential': password,
        'username': username
      };
    }
    return iceServer;
  };

  // Creates an ICEServer object from multiple URLs.
  window.createIceServers = function(urls, username, password) {
    return {
      'urls': urls,
      'credential': password,
      'username': username
    };
  };

  // The RTCPeerConnection object.
  RTCPeerConnection = function(pcConfig, pcConstraints) {
    return new webkitRTCPeerConnection(pcConfig, pcConstraints);
  };

  // Get UserMedia (only difference is the prefix).
  // Code from Adam Barth.
  getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
  navigator.getUserMedia = getUserMedia;

  // Attach a media stream to an element.
  attachMediaStream = function(element, stream) {
    if (typeof element.srcObject !== 'undefined') {
      element.srcObject = stream;
    } else if (typeof element.mozSrcObject !== 'undefined') {
      element.mozSrcObject = stream;
    } else if (typeof element.src !== 'undefined') {
      element.src = URL.createObjectURL(stream);
    } else {
      console.log('Error attaching stream to element.');
    }
  };

  reattachMediaStream = function(to, from) {
    to.src = from.src;
  };
} else {
  console.log('Browser does not appear to be WebRTC-capable');
}

// Returns the result of getUserMedia as a Promise.
function requestUserMedia(constraints) {
  return new Promise(function(resolve, reject) {
    try {
      getUserMedia(constraints, resolve, reject);
    } catch (e) {
      reject(e);
    }
  });
}

if (typeof module !== 'undefined') {
  module.exports = {
    RTCPeerConnection: RTCPeerConnection,
    getUserMedia: getUserMedia,
    attachMediaStream: attachMediaStream,
    reattachMediaStream: reattachMediaStream,
    webrtcDetectedBrowser: webrtcDetectedBrowser,
    webrtcDetectedVersion: webrtcDetectedVersion
    //requestUserMedia: not exposed on purpose.
    //trace: not exposed on purpose.
  };
}
<|endoftext|>


<commit_before>(function (angular, buildfire) {
  angular
    .module('mediaCenterRSSPluginWidget')

  /****************
   *  directives  *
   ****************/

  /**
   * A directive which is used to render ng-repeat when data received.
   */
    .directive("triggerNgRepeatRender", [function () {
      var linker = function (scope, elem, attrs) {
        var a = $(elem).width();
      };
      return {
        restrict: 'A',
        link: linker
      };
    }])
  /**
   * A directive which is used handle background image for layouts.
   */
      .directive('backImg', ["$rootScope", function ($rootScope) {
          return function (scope, element, attrs) {
              attrs.$observe('backImg', function (value) {
                  var img = '';
                  if (value) {
                      buildfire.imageLib.local.cropImage(value, {
                          width: $rootScope.deviceWidth,
                          height: $rootScope.deviceHeight
                      }, function (err, imgUrl) {
                          if(imgUrl) {
                              img = imgUrl;
                              element.attr("style", 'background:url(' + img + ') !important');
                          } else {
                              img = '';
                              element.attr("style", 'background-color:white');
                          }
                          element.css({
                              'background-size': 'cover !important'
                          });
                      });
//                      img = $filter("cropImage")(value, $rootScope.deviceWidth, $rootScope.deviceHeight, true);
                  }
                  else {
                      img = "";
                      element.attr("style", 'background-color:white');
                      element.css({
                          'background-size': 'cover !important'
                      });
                  }
              });
          };
      }])

  /**
   * A directive which is used handle background image for layouts.
   */
    /*.directive("backgroundImage", ['$filter', function ($filter) {
      var linker = function (scope, element, attrs) {
        element.css('min-height', '580px');
        var getImageUrlFilter = $filter("resizeImage");
        var setBackgroundImage = function (backgroundImage) {
          if (backgroundImage) {
            element.css(
              'background', '#010101 url('
              + getImageUrlFilter(backgroundImage, 342, 770, 'resize')
              + ') repeat fixed top center');
          } else {
            element.css('background', 'none');
          }
        };
        attrs.$observe('backgroundImage', function (newValue) {
          setBackgroundImage(newValue);
        });
      };
      return {
        restrict: 'A',
        link: linker
      };
    }])*/

  /**
   * A directive which is used to initiate carousel when image items received.
   */
      .directive("buildFireCarousel", ["$rootScope", function ($rootScope) {
          return {
              restrict: 'A',
              link: function (scope, elem, attrs) {
                  $rootScope.$broadcast("Carousel:LOADED");
              }
          };
      }])
})(window.angular, window.buildfire);
<commit_msg>fixed background issue<commit_after>(function (angular, buildfire) {
  angular
    .module('mediaCenterRSSPluginWidget')

  /****************
   *  directives  *
   ****************/

  /**
   * A directive which is used to render ng-repeat when data received.
   */
    .directive("triggerNgRepeatRender", [function () {
      var linker = function (scope, elem, attrs) {
        var a = $(elem).width();
      };
      return {
        restrict: 'A',
        link: linker
      };
    }])
  /**
   * A directive which is used handle background image for layouts.
   */
      .directive('backImg', ["$rootScope", function ($rootScope) {
          return function (scope, element, attrs) {
              attrs.$observe('backImg', function (value) {
                  var img = '';
                  if (value) {
                      buildfire.imageLib.local.cropImage(value, {
                          width: $rootScope.deviceWidth,
                          height: $rootScope.deviceHeight
                      }, function (err, imgUrl) {
                          if(imgUrl) {
                              img = imgUrl;
                              element.attr("style", 'background:url(' + img + ') !important;background-size:cover !important');
                          } else {
                              img = '';
                              element.attr("style", 'background-color:white');
                          }
                          element.css({
                              'background-size': 'cover !important'
                          });
                      });
//                      img = $filter("cropImage")(value, $rootScope.deviceWidth, $rootScope.deviceHeight, true);
                  }
                  else {
                      img = "";
                      element.attr("style", 'background-color:white');
                      element.css({
                          'background-size': 'cover !important'
                      });
                  }
              });
          };
      }])

  /**
   * A directive which is used handle background image for layouts.
   */
    /*.directive("backgroundImage", ['$filter', function ($filter) {
      var linker = function (scope, element, attrs) {
        element.css('min-height', '580px');
        var getImageUrlFilter = $filter("resizeImage");
        var setBackgroundImage = function (backgroundImage) {
          if (backgroundImage) {
            element.css(
              'background', '#010101 url('
              + getImageUrlFilter(backgroundImage, 342, 770, 'resize')
              + ') repeat fixed top center');
          } else {
            element.css('background', 'none');
          }
        };
        attrs.$observe('backgroundImage', function (newValue) {
          setBackgroundImage(newValue);
        });
      };
      return {
        restrict: 'A',
        link: linker
      };
    }])*/

  /**
   * A directive which is used to initiate carousel when image items received.
   */
      .directive("buildFireCarousel", ["$rootScope", function ($rootScope) {
          return {
              restrict: 'A',
              link: function (scope, elem, attrs) {
                  $rootScope.$broadcast("Carousel:LOADED");
              }
          };
      }])
})(window.angular, window.buildfire);
<|endoftext|>


<commit_before>/*
 * ==================================================
 * Responses
 * ==================================================
 *
 * Collects responses from web, mobile, and paper forms.
 *
 * Data structure for paper-originating response:
 * responses: [
 *   { parcel_id: "3728049",
 *     responses: {"type":3,"business":1},
 *     id: "cf1fa4c0-8e9e-11e1-8159-e53f8dbd1a6a",
 *     survey: "e458a930-8e27-11e1-b08f-37bd5a7df741",
 *     source : {type : "paper", scan: "", form: ""}
 *   }
 * ]
 * Data structure for mobile-originating response:
 * responses: [
 *   { parcel_id: "3728049",
 *     responses: {"type":3,"business":1},
 *     id: "cf1fa4c0-8e9e-11e1-8159-e53f8dbd1a6a",
 *     survey: "e458a930-8e27-11e1-b08f-37bd5a7df741",
 *     source : {type : "mobile"}
 *   }
 * ]
 *
 */

var util = require('./util');

module.exports = {
  setup: setup
};

var handleError = util.handleError;
var isArray = util.isArray;

/*
 * app: express server
 * db: mongodb database
 * idgen: unique ID generator
 * collectionName: name of responses collection
 */
function setup(app, db, idgen, collectionName) {
  function getCollection(cb) {
    return db.collection(collectionName, cb);
  }

  // Get all responses for a survey.
  // GET http://localhost:3000/surveys/{SURVEY ID}/responses
  // GET http://localhost:3000/surveys/1/responses
  app.get('/surveys/:sid/responses', function(req, response) {
    var surveyid = req.params.sid;
    getCollection(function(err, collection) {
      collection.find({'survey': surveyid}, function(err, cursor) {
        if (err != null) {
          console.log('Error retrieving responses for survey ' + surveyid + ': ' + err.message);
          response.send();
          return;
        }
        cursor.toArray(function(err, items) {
          response.send({responses: items});
        });
      });
    });
  });

  // Get all responses for a specific parcel.
  // TODO: At some point, parcel should become a generic geographic object ID.
  // GET http://localhost:3000/surveys/{SURVEY ID}/parcels/{PARCEL ID}/responses
  // GET http://localhost:3000/surveys/1/parcels/3728048/responses
  app.get('/surveys/:sid/parcels/:parcel_id/responses', function(req, response) {
    var surveyid = req.params.sid;
    var parcel_id = req.params.parcel_id;
    getCollection(function(err, collection) {
      collection.find({'survey': surveyid, 'parcel_id': parcel_id}, function(err, cursor) {
        if (err != null) {
          console.log('Error retrieving responses for survey ' + surveyid + ': ' + err.message);
          response.send();
          return;
        }
        cursor.toArray(function(err, items) {
          response.send({responses: items});
        });
      });
    });
  });

  // Get a response for a survey.
  // GET http://localhost:3000/surveys/{SURVEY ID}/responses/{RESPONSE ID}
  // GET http://localhost:3000/surveys/1/responses/2ec140e0-827f-11e1-83d8-bf682a6ee038
  app.get('/surveys/:sid/responses/:rid', function(req, response) {
    var surveyid = req.params.sid;
    var responseid = req.params.rid;
    getCollection(function(err, collection) {
      collection.find({'survey': surveyid, 'id': responseid}, function(err, cursor) {
        if (handleError(err, response)) return;

        cursor.toArray(function(err, items) {
          if (items.length > 1) {
            console.log('!!! WARNING: There should only be one response with a given id attached to a survey.');
            console.log('!!! Found ' + items.length);
            console.log('!!! Responses: ' + JSON.stringify(items));
          }
          if (items.length > 0) {
            response.send({response: items[0]});
          } else {
            response.send({});
          }
        });
      });
    });
  });

  // Delete a response from a survey
  // DELETE http://localhost:3000/surveys/{SURVEY ID}/responses/{RESPONSE ID}
  app.del('/surveys/:sid/responses/:rid', function(req, response) {
    var survey = req.params.sid;
    var id = req.params.rid;
    console.log('Removing response ' + id + ' from the database.');
    getCollection(function(err, collection) {
      collection.remove({survey: survey, id: id}, {safe: true}, function(error, count) {
        if (error != null) {
          console.log('Error removing response ' + id + ' for survey ' + survey + ' from the response collection: ' + err.message);
          response.send();
        } else {
          if (count != 1) {
            console.log('!!! We should have removed exactly 1 entry. Instead we removed ' + count + ' entries.');
          }
          response.send({count: count});
        }
      });
    });
  });

  // Add responses for a survey.
  // POST http://localhost:3000/surveys/{SURVEY ID}/reponses
  // POST http://localhost:3000/surveys/1/reponses
  // Expects data in the format:
  // responses: [
  //  { parcels: [ {parcel_id: '10', responses: {'Q0': 0, 'Q1': 3}} ]}, ...]
  app.post('/surveys/:sid/responses', function(req, response) {
    var resps = req.body.responses;
    var total = resps.length;

    console.log(resps);
    console.log('Adding ' + total + ' responses to the database.');

    var count = 0;
    getCollection(function(err, collection) {
      var surveyid = req.params.sid;

      // Iterate over each survey response we received.
      resps.forEach(function(resp) {

        // Add metadata to the survey response
        var id = idgen();
        resp.id = id;
        resp.survey = surveyid;
        resp.created = new Date();

        // check if there is a centroid. if yes, make sure the values are floats
        // TODO: abstract into a testable function.
        var centroid = resp["geo_info"]["centroid"];
        if (centroid !== undefined) {
          centroid[0] = parseFloat(centroid[0]);
          centroid[1] = parseFloat(centroid[1]);
        };

        // Add response to database.
        collection.insert(resp, function() {
          console.log(resp);
          // Check if we've added all of them.
          if (++count == total) {
            console.log('Created ' + total + 'items. Returning.');
            response.send({responses: resps}, 201);
          }
        });
      });
    });
  });

  // Delete all responses for a survey.
  // This is maintainence functionality. Regular clients should not delete forms.
  // DELETE http://localhost:3000/surveys/{SURVEY ID}/reponses
  // DELETE http://localhost:3000/surveys/1/reponses
  app.del('/surveys/:sid/responses', function(req, response) {
    var survey = req.params.sid;
    console.log('!!! Deleting responses for survey ' + survey + ' from the database.');
    getCollection(function(err, collection) {
      collection.remove({survey: survey}, {safe: true}, function(error, count) {
        if (error != null) {
          console.log('Error removing responses for survey ' + survey + ' from the response collection: ' + err.message);
          response.send();
        } else {
          response.send({count: count});
        }
      });
    });
  });

  // Get all responses in a bounding box
  // GET http://localhost:3000/surveys/{SURVEY ID}/reponses/in/lower-left lat,lower-left lng, upper-right lat, upper-right lng
  // GET http://localhost:3000/surveys/{SURVEY ID}/reponses/in/1,2,3,4
  app.get('/surveys/:sid/responses/in/:bounds', function(req, response) {
    var surveyid = req.params.sid;
    var bounds = req.params.bounds;
    var coords = bounds.split(",");
    if (coords.length != 4) {
      // There need to be four points.
      response.send(s400);
    };
    for (var i = -1, ln = coords.length; ++i < ln;) {
      coords[i] = parseFloat(coords[i]);
    };

    var bbox = [[coords[0], coords[1]], [coords[2],  coords[3]]];
    query = {'survey': surveyid, 'geo_info.centroid': {"$within": { "$box": bbox}}};
    console.log("Bounds query ====================");
    console.log(query['geo_info.centroid']['$within']["$box"]);

    getCollection(function(err, collection) {
      collection.find(query, function(err, cursor) {
        if (handleError(err, response)) return;

        cursor.toArray(function(err, items) {
          console.log("Bounds results =========");
          console.log(items);
          if (items.length > 0) {
            response.send({"responses":items});
          } else {
            response.send({});
          }
        });
      });
    });
  });

  function commasep(row, headers, headerCount) {
    var arr = [];
    for (var i = 0; i < row.length; i++) {
      if (headerCount[headers[i]] === 1) {
        // No multiple-choice for this column
        arr.push(row[i]);
      } else {
        var len;
        if (!isArray(row[i])) {
          arr.push(row[i]);
          len = 1;
        } else {
          len = row[i].length;
          for (var j = 0; j < len; j++) {
            arr.push(row[i][j]);
          }
        }
        // Padding for multiple-choice situations
        for (var h = 0; h < headerCount[headers[i]] - len; h++) {
          arr.push(null);
        }
      }
    }

    return arr.join(',');
  }

  // Return response data as CSV
  // GET http://localhost:5000/surveys/{SURVEY ID}/csv
  app.get('/surveys/:sid/csv', function(req, response) {
    var sid = req.params.sid;
    getCollection(function(err, collection) {
      collection.find({'survey': sid}, function(err, cursor) {
        if (err != null) {
          console.log('Error retrieving responses for survey ' + surveyid + ': ' + err.message);
          response.send(500);
          return;
        }
        cursor.toArray(function(err, items) {
          var headers = ['parcel_id', 'source'];
          var headerIndices = {};
          var headerCount = {};
          var i;
          for (i = 0; i < headers.length; i++) {
            headerIndices[headers[i]] = i;
            headerCount[headers[i]] = 1;
          }
          var rows = [];
          var len = items.length;
          // Iterate over each response
          for (i = 0; i < len; i++) {
            var responses = items[i].responses;

            // Add context entries (parcel ID, source type)
            var row = [items[i].parcel_id, items[i].source.type];

            for (var resp in responses) {
              if (responses.hasOwnProperty(resp)) {
                // If we haven't encountered this column, track it.
                if (!headerIndices.hasOwnProperty(resp)) {
                  headerIndices[resp] = headers.length;
                  headerCount[resp] = 1;
                  headers.push(resp);
                  // Add an empty entry to each existing row, since they didn't
                  // have this column.
                  for (var j = 0; j < rows.length; j++) {
                    rows[j].push('');
                  }
                }
                var entry = responses[resp];
                // Check if we have multiple answers.
                if (isArray(entry)) {
                  if (entry.length > headerCount[resp]) {
                    headerCount[resp] = entry.length;
                  }
                }
                // Add the response to the CSV row.
                row[headerIndices[resp]] = responses[resp];
              }
            }
            // Add the CSV row.
            rows.push(row);
          }

          response.writeHead(200, {
            'Content-Type': 'text/csv'
          });
          // Turn each row into a CSV line
          response.write(commasep(headers, headers, headerCount));
          response.write('\n');
          for (i = 0; i < len; i++) {
            response.write(commasep(rows[i], headers, headerCount));
            response.write('\n');
          }
          response.end();
        });
      });
    });
  });

} // setup()
<commit_msg>Check for null in geo query.<commit_after>/*
 * ==================================================
 * Responses
 * ==================================================
 *
 * Collects responses from web, mobile, and paper forms.
 *
 * Data structure for paper-originating response:
 * responses: [
 *   { parcel_id: "3728049",
 *     responses: {"type":3,"business":1},
 *     id: "cf1fa4c0-8e9e-11e1-8159-e53f8dbd1a6a",
 *     survey: "e458a930-8e27-11e1-b08f-37bd5a7df741",
 *     source : {type : "paper", scan: "", form: ""}
 *   }
 * ]
 * Data structure for mobile-originating response:
 * responses: [
 *   { parcel_id: "3728049",
 *     responses: {"type":3,"business":1},
 *     id: "cf1fa4c0-8e9e-11e1-8159-e53f8dbd1a6a",
 *     survey: "e458a930-8e27-11e1-b08f-37bd5a7df741",
 *     source : {type : "mobile"}
 *   }
 * ]
 *
 */

var util = require('./util');

module.exports = {
  setup: setup
};

var handleError = util.handleError;
var isArray = util.isArray;

/*
 * app: express server
 * db: mongodb database
 * idgen: unique ID generator
 * collectionName: name of responses collection
 */
function setup(app, db, idgen, collectionName) {
  function getCollection(cb) {
    return db.collection(collectionName, cb);
  }

  // Get all responses for a survey.
  // GET http://localhost:3000/surveys/{SURVEY ID}/responses
  // GET http://localhost:3000/surveys/1/responses
  app.get('/surveys/:sid/responses', function(req, response) {
    var surveyid = req.params.sid;
    getCollection(function(err, collection) {
      collection.find({'survey': surveyid}, function(err, cursor) {
        if (err != null) {
          console.log('Error retrieving responses for survey ' + surveyid + ': ' + err.message);
          response.send();
          return;
        }
        cursor.toArray(function(err, items) {
          response.send({responses: items});
        });
      });
    });
  });

  // Get all responses for a specific parcel.
  // TODO: At some point, parcel should become a generic geographic object ID.
  // GET http://localhost:3000/surveys/{SURVEY ID}/parcels/{PARCEL ID}/responses
  // GET http://localhost:3000/surveys/1/parcels/3728048/responses
  app.get('/surveys/:sid/parcels/:parcel_id/responses', function(req, response) {
    var surveyid = req.params.sid;
    var parcel_id = req.params.parcel_id;
    getCollection(function(err, collection) {
      collection.find({'survey': surveyid, 'parcel_id': parcel_id}, function(err, cursor) {
        if (err != null) {
          console.log('Error retrieving responses for survey ' + surveyid + ': ' + err.message);
          response.send();
          return;
        }
        cursor.toArray(function(err, items) {
          response.send({responses: items});
        });
      });
    });
  });

  // Get a response for a survey.
  // GET http://localhost:3000/surveys/{SURVEY ID}/responses/{RESPONSE ID}
  // GET http://localhost:3000/surveys/1/responses/2ec140e0-827f-11e1-83d8-bf682a6ee038
  app.get('/surveys/:sid/responses/:rid', function(req, response) {
    var surveyid = req.params.sid;
    var responseid = req.params.rid;
    getCollection(function(err, collection) {
      collection.find({'survey': surveyid, 'id': responseid}, function(err, cursor) {
        if (handleError(err, response)) return;

        cursor.toArray(function(err, items) {
          if (items.length > 1) {
            console.log('!!! WARNING: There should only be one response with a given id attached to a survey.');
            console.log('!!! Found ' + items.length);
            console.log('!!! Responses: ' + JSON.stringify(items));
          }
          if (items.length > 0) {
            response.send({response: items[0]});
          } else {
            response.send({});
          }
        });
      });
    });
  });

  // Delete a response from a survey
  // DELETE http://localhost:3000/surveys/{SURVEY ID}/responses/{RESPONSE ID}
  app.del('/surveys/:sid/responses/:rid', function(req, response) {
    var survey = req.params.sid;
    var id = req.params.rid;
    console.log('Removing response ' + id + ' from the database.');
    getCollection(function(err, collection) {
      collection.remove({survey: survey, id: id}, {safe: true}, function(error, count) {
        if (error != null) {
          console.log('Error removing response ' + id + ' for survey ' + survey + ' from the response collection: ' + err.message);
          response.send();
        } else {
          if (count != 1) {
            console.log('!!! We should have removed exactly 1 entry. Instead we removed ' + count + ' entries.');
          }
          response.send({count: count});
        }
      });
    });
  });

  // Add responses for a survey.
  // POST http://localhost:3000/surveys/{SURVEY ID}/reponses
  // POST http://localhost:3000/surveys/1/reponses
  // Expects data in the format:
  // responses: [
  //  { parcels: [ {parcel_id: '10', responses: {'Q0': 0, 'Q1': 3}} ]}, ...]
  app.post('/surveys/:sid/responses', function(req, response) {
    var resps = req.body.responses;
    var total = resps.length;

    console.log(resps);
    console.log('Adding ' + total + ' responses to the database.');

    var count = 0;
    getCollection(function(err, collection) {
      var surveyid = req.params.sid;

      // Iterate over each survey response we received.
      resps.forEach(function(resp) {

        // Add metadata to the survey response
        var id = idgen();
        resp.id = id;
        resp.survey = surveyid;
        resp.created = new Date();

        // check if there is a centroid. if yes, make sure the values are floats
        // TODO: abstract into a testable function.
        var centroid = resp["geo_info"]["centroid"];
        if (centroid !== undefined) {
          centroid[0] = parseFloat(centroid[0]);
          centroid[1] = parseFloat(centroid[1]);
        }

        // Add response to database.
        collection.insert(resp, function() {
          console.log(resp);
          // Check if we've added all of them.
          if (++count == total) {
            console.log('Created ' + total + 'items. Returning.');
            response.send({responses: resps}, 201);
          }
        });
      });
    });
  });

  // Delete all responses for a survey.
  // This is maintainence functionality. Regular clients should not delete forms.
  // DELETE http://localhost:3000/surveys/{SURVEY ID}/reponses
  // DELETE http://localhost:3000/surveys/1/reponses
  app.del('/surveys/:sid/responses', function(req, response) {
    var survey = req.params.sid;
    console.log('!!! Deleting responses for survey ' + survey + ' from the database.');
    getCollection(function(err, collection) {
      collection.remove({survey: survey}, {safe: true}, function(error, count) {
        if (error != null) {
          console.log('Error removing responses for survey ' + survey + ' from the response collection: ' + err.message);
          response.send();
        } else {
          response.send({count: count});
        }
      });
    });
  });

  // Get all responses in a bounding box
  // GET http://localhost:3000/surveys/{SURVEY ID}/reponses/in/lower-left lat,lower-left lng, upper-right lat, upper-right lng
  // GET http://localhost:3000/surveys/{SURVEY ID}/reponses/in/1,2,3,4
  app.get('/surveys/:sid/responses/in/:bounds', function(req, response) {
    var surveyid = req.params.sid;
    var bounds = req.params.bounds;
    var coords = bounds.split(",");
    if (coords.length != 4) {
      // There need to be four points.
      response.send(400);
    }
    for (var i = -1, ln = coords.length; ++i < ln;) {
      coords[i] = parseFloat(coords[i]);
    }

    var bbox = [[coords[0], coords[1]], [coords[2],  coords[3]]];
    query = {'survey': surveyid, 'geo_info.centroid': {"$within": { "$box": bbox}}};
    console.log("Bounds query ====================");
    console.log(query['geo_info.centroid']['$within']["$box"]);

    getCollection(function(err, collection) {
      collection.find(query, function(err, cursor) {
        if (handleError(err, response)) return;

        cursor.toArray(function(err, items) {
          console.log("Bounds results =========");
          console.log(items);
          if (!items || items.length === 0) {
            response.send({});
            return;
          }
          response.send({'responses': items});
        });
      });
    });
  });

  function commasep(row, headers, headerCount) {
    var arr = [];
    for (var i = 0; i < row.length; i++) {
      if (headerCount[headers[i]] === 1) {
        // No multiple-choice for this column
        arr.push(row[i]);
      } else {
        var len;
        if (!isArray(row[i])) {
          arr.push(row[i]);
          len = 1;
        } else {
          len = row[i].length;
          for (var j = 0; j < len; j++) {
            arr.push(row[i][j]);
          }
        }
        // Padding for multiple-choice situations
        for (var h = 0; h < headerCount[headers[i]] - len; h++) {
          arr.push(null);
        }
      }
    }

    return arr.join(',');
  }

  // Return response data as CSV
  // GET http://localhost:5000/surveys/{SURVEY ID}/csv
  app.get('/surveys/:sid/csv', function(req, response) {
    var sid = req.params.sid;
    getCollection(function(err, collection) {
      collection.find({'survey': sid}, function(err, cursor) {
        if (err != null) {
          console.log('Error retrieving responses for survey ' + surveyid + ': ' + err.message);
          response.send(500);
          return;
        }
        cursor.toArray(function(err, items) {
          var headers = ['parcel_id', 'source'];
          var headerIndices = {};
          var headerCount = {};
          var i;
          for (i = 0; i < headers.length; i++) {
            headerIndices[headers[i]] = i;
            headerCount[headers[i]] = 1;
          }
          var rows = [];
          var len = items.length;
          // Iterate over each response
          for (i = 0; i < len; i++) {
            var responses = items[i].responses;

            // Add context entries (parcel ID, source type)
            var row = [items[i].parcel_id, items[i].source.type];

            for (var resp in responses) {
              if (responses.hasOwnProperty(resp)) {
                // If we haven't encountered this column, track it.
                if (!headerIndices.hasOwnProperty(resp)) {
                  headerIndices[resp] = headers.length;
                  headerCount[resp] = 1;
                  headers.push(resp);
                  // Add an empty entry to each existing row, since they didn't
                  // have this column.
                  for (var j = 0; j < rows.length; j++) {
                    rows[j].push('');
                  }
                }
                var entry = responses[resp];
                // Check if we have multiple answers.
                if (isArray(entry)) {
                  if (entry.length > headerCount[resp]) {
                    headerCount[resp] = entry.length;
                  }
                }
                // Add the response to the CSV row.
                row[headerIndices[resp]] = responses[resp];
              }
            }
            // Add the CSV row.
            rows.push(row);
          }

          response.writeHead(200, {
            'Content-Type': 'text/csv'
          });
          // Turn each row into a CSV line
          response.write(commasep(headers, headers, headerCount));
          response.write('\n');
          for (i = 0; i < len; i++) {
            response.write(commasep(rows[i], headers, headerCount));
            response.write('\n');
          }
          response.end();
        });
      });
    });
  });

} // setup()
<|endoftext|>


<commit_before>module.exports = {
    metadata: {
        family: "tiSensorTag",
        plugin: "tiSensorTag",
        label: "Texas Instruments (C) CC2540/CC2650 SensorTag",
        manufacturer: "Texas Instruments",
        tangible: true,
        discoverable: true,
        state: [{
            id: "humidity",
            label: "Humidity (%)",
            type: {
                id: "number"
            }
        }, {
            id: "ambientTemperature",
            label: "Ambient Temperature (°C)",
            type: {
                id: "number"
            }
        }, {
            id: "objectTemperature",
            label: "Object Temperature (°C)",
            type: {
                id: "number"
            }
        }, {
            id: "barometricPressure",
            label: "Barometric Pressure (mBar)",
            type: {
                id: "number"
            }
        }, {
            id: "luminousIntensity",
            label: "Luminous Intensity (Lux)",
            type: {
                id: "number"
            }
        }],
        actorTypes: [],
        sensorTypes: [],
        services: [],
        configuration: [{
            id: "barometricPressureEnabled",
            label: "Barometric Pressure Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "irTemperatureEnabled",
            label: "IR Temperature Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "ambientTemperatureEnabled",
            label: "Ambient Temperature Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "accelerometerEnabled",
            label: "Accelerometer Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "gyroscopeEnabled",
            label: "Gyroscope Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "magnetometerEnabled",
            label: "Magnetometer Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "humidityEnabled",
            label: "Humidity Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "humidityNotificationInterval",
            label: "Humidity Notification Interval (ms)",
            type: {
                id: "integer"
            },
            defaultValue: 60000
        }, {
            id: "luxometerEnabled",
            label: "Luxometer Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "luxometerNotificationInterval",
            label: "Luxometer Notification Interval (ms)",
            type: {
                id: "integer"
            },
            defaultValue: 60000
        }]
    },
    create: function (device) {
        return new TISensorTag();
    },
    discovery: function (options) {
        var discovery = new TISensorTagDiscovery();

        discovery.options = options;

        return discovery;
    }
};

var q = require('q');
var SensorTag = require("sensortag");

function TISensorTagDiscovery() {
    /**
     *
     * @param options
     */
    TISensorTagDiscovery.prototype.start = function () {
        if (this.node.isSimulated()) {
        } else {
            SensorTag.discover(function (sensorTag) {
                var tiSensorTag = new TISensorTag();

                tiSensorTag.sensorTag = sensorTag;
                tiSensorTag.uuid = sensorTag.uuid;
            });
        }
    };

    /**
     *
     * @param options
     */
    TISensorTagDiscovery.prototype.stop = function () {
    };
}

/**
 *
 */
function TISensorTag() {
    /**
     *
     */
    TISensorTag.prototype.start = function () {
        var deferred = q.defer();

        this.state = {
            acceleration: {x: null, y: null, z: null},
            barometricPressure: null,
            gyroscopicPropulsion: {x: null, y: null, z: null},
            humidity: null,
            irTemperature: null,
            ambientTemperature: null,
            magneticFieldStrength: {x: null, y: null, z: null},
            luminousIntensity: null
        };

        if (this.sensorTag) {
            this.connect();

            deferred.resolve();
        }
        else {
            if (!this.isSimulated()) {
                if (!SensorTag) {
                    SensorTag = require("sensortag");
                }

                this.scan();

                deferred.resolve();
            } else {
                setInterval(function () {
                    this.state = {
                        acceleration: {
                            x: Math.floor((Math.random() * 10)),
                            y: Math.floor((Math.random() * 10)),
                            z: Math.floor((Math.random() * 10))
                        },
                        barometricPressure: 1000 + Math.floor((Math.random() * 200)),
                        gyroscopicPropulsion: {
                            x: Math.floor((Math.random() * 50)),
                            y: Math.floor((Math.random() * 50)),
                            z: Math.floor((Math.random() * 50))
                        },
                        humidity: 60 + Math.floor((Math.random() * 10)),
                        irTemperature: 20 + Math.floor((Math.random() * 10)),
                        ambientTemperature: 20 + Math.floor((Math.random() * 10)),
                        magneticFieldStrength: {
                            x: Math.floor((Math.random() * 10)),
                            y: Math.floor((Math.random() * 10)),
                            z: Math.floor((Math.random() * 10))
                        },
                        luminousIntensity: 1500 + Math.floor((Math.random() * 10))
                    };

                    this.publishStateChange();
                }.bind(this), 1000);

                deferred.resolve();
            }
        }

        return deferred.promise;
    };

    /**
     *
     */
    TISensorTag.prototype.scan = function () {
        console.log("\tScanning started.");

        SensorTag.discover(function (sensorTag) {
            if (sensorTag.uuid === this.configuration.uuid) {
                console.log("\nMatching Tag found.");

                this.sensorTag = sensorTag;

                this.sensorTag.on('disconnect', function () {
                    console.log('\nDisconnected.');
                    this.scan();
                }.bind(this));

                this.connect();
            }
        }.bind(this));
    };

    /**
     *
     */
    TISensorTag.prototype.connect = function () {
        this.sensorTag.connectAndSetUp(function () {
            this.sensorTag.readDeviceName(function (error, deviceName) {
                console.log('\tdevice name = ' + deviceName);
            }.bind(this));
            this.sensorTag.readManufacturerName(function (error, manufacturerName) {
                console.log('\tmanufacturer name = ' + manufacturerName);
            }.bind(this));
            this.sensorTag.readSystemId(function (error, systemId) {
                console.log('\tsystem ID = ' + systemId);
            }.bind(this));
            this.sensorTag.readSerialNumber(function (error, serialNumber) {
                console.log('\tserial number = ' + serialNumber);
            }.bind(this));

            // Temperatures

            this.sensorTag.enableIrTemperature(function () {
                this.sensorTag.on('irTemperatureChange', function (objectTemperature, ambientTemperature) {
                    this.state.objectTemperatur = objectTemperature.toFixed(1);
                    this.state.ambientTemperatur = ambientTemperature.toFixed(1);

                    this.publishStateChange();
                }.bind(this));
            }.bind(this));

            // Accelerometer

            if (this.configuration.accelerometerEnabled) {
                this.sensorTag.enableAccelerometer(function () {
                    this.sensorTag.on("accelerometerChange", function (x, y, z) {
                        this.state.acceleration.x = x.toFixed(1);
                        this.state.acceleration.y = y.toFixed(1);
                        this.state.acceleration.z = z.toFixed(1);

                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Gyroscope

            if (this.configuration.gyroscopeEnabled) {
                this.sensorTag.enableGyroscope(function () {
                    this.sensorTag.on("gyroscopeChange", function (x, y, z) {
                        this.state.gyroscopicPropulsion.x = x.toFixed(1);
                        this.state.gyroscopicPropulsion.y = y.toFixed(1);
                        this.state.gyroscopicPropulsion.z = z.toFixed(1);

                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Magnetometer

            if (this.configuration.magnetometerEnabled) {
                this.sensorTag.enableMagnetometer(function () {
                    this.sensorTag.on("magnetometerChange", function (x, y, z) {
                        this.state.magneticFieldStrength.x = x.toFixed(1);
                        this.state.magneticFieldStrength.y = y.toFixed(1);
                        this.state.magneticFieldStrength.z = z.toFixed(1);

                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Humidity

            if (this.configuration.humidityEnabled) {
                this.sensorTag.enableHumidity(function () {
                    if (this.configuration.humidityNotificationInterval > 0) {
                        this.sensorTag.setHumidityPeriod(this.configuration.humidityNotificationInterval, function (error) {
                            this.sensorTag.notifyHumidity(function (error, humidity) {
                                if (humidity) {
                                    this.state.humidity = humidity.toFixed(1);
                                    this.publishStateChange();
                                }
                            }.bind(this));
                        }.bind(this));
                    }

                    this.sensorTag.on("humidityChange", function (humidity) {
                        this.state.humidity = humidity.toFixed(1);
                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Barometric Pressure

            if (this.configuration.barometricPressureEnabled) {
                this.sensorTag.enableBarometricPressure(function () {
                    if (this.configuration.barometricPressureNotificationInterval > 0) {
                        this.sensorTag.setBarometricPressurePeriod(this.configuration.barometricPressureNotificationInterval, function (error) {
                            this.sensorTag.notifyBarometricPressure(function (error, barometricPressure) {
                                if (barometricPressure) {
                                    this.state.barometricPressure = barometricPressure.toFixed(1);

                                    this.publishStateChange();
                                }
                            }.bind(this));
                        }.bind(this));
                    }
                    this.sensorTag.on("barometricChange", function (barometricPressure) {
                        this.state.barometricPressure = barometricPressure.toFixed(1);
                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Luxometer

            if (this.sensorTag.type != "cc2540" && this.configuration.luxometerEnabled) {
                this.sensorTag.enableLuxometer(function () {
                    if (this.configuration.luxometerNotificationInterval > 0) {
                        this.sensorTag.setLuxometerPeriod(this.configuration.luxometerNotificationInterval, function (error) {
                            this.sensorTag.notifyLuxometer(function (error, luminousIntensity) {
                                this.state.luminousIntensity = luminousIntensity.toFixed(1);
                                this.publishStateChange();
                            }.bind(this));
                        }.bind(this));
                    }

                    this.sensorTag.on("luxometerChange", function (luminousIntensity) {
                        this.state.luminousIntensity = luminousIntensity.toFixed(1);
                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Simple Keys

            this.sensorTag.on("simpleKeyChange", function (left, right) {
                console.log("Keys", left, right);

                if (left) {
                    this.publishEvent("left");
                }

                if (right) {
                    this.publishEvent("right");
                }
            }.bind(this));
        }.bind(this));
    };

    /**
     *
     */
    TISensorTag.prototype.scalarDeviation = function (value, lastValue) {
        return Math.abs(lastValue - value) / lastValue;
    };

    /**
     *
     */
    TISensorTag.prototype.vectorDeviation = function (value, lastValue) {
        var percentage = Math.sqrt(Math.pow(lastValue.x - value.x, 2) + Math.pow(lastValue.y - value.y, 2) + Math.pow(lastValue.z - value.z, 2)) /
            Math.sqrt(Math.pow(lastValue.x, 2) + Math.pow(lastValue.y, 2) + Math.pow(lastValue.z, 2));

        return percentage;
    };

    /**
     *
     */
    TISensorTag.prototype.setState = function (state) {
        this.state = state;
    };

    /**
     *
     */
    TISensorTag.prototype.getState = function () {
        return this.state;
    };
}
<commit_msg>Made UUID part of configuration.<commit_after>module.exports = {
    metadata: {
        family: "tiSensorTag",
        plugin: "tiSensorTag",
        label: "Texas Instruments (C) CC2540/CC2650 SensorTag",
        manufacturer: "Texas Instruments",
        tangible: true,
        discoverable: true,
        state: [{
            id: "humidity",
            label: "Humidity (%)",
            type: {
                id: "number"
            }
        }, {
            id: "ambientTemperature",
            label: "Ambient Temperature (°C)",
            type: {
                id: "number"
            }
        }, {
            id: "objectTemperature",
            label: "Object Temperature (°C)",
            type: {
                id: "number"
            }
        }, {
            id: "barometricPressure",
            label: "Barometric Pressure (mBar)",
            type: {
                id: "number"
            }
        }, {
            id: "luminousIntensity",
            label: "Luminous Intensity (Lux)",
            type: {
                id: "number"
            }
        }],
        actorTypes: [],
        sensorTypes: [],
        services: [],
        configuration: [{
            id: "uuid",
            label: "UUID",
            type: {
                id: "string"
            }
        }, {
            id: "barometricPressureEnabled",
            label: "Barometric Pressure Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "irTemperatureEnabled",
            label: "IR Temperature Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "ambientTemperatureEnabled",
            label: "Ambient Temperature Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "accelerometerEnabled",
            label: "Accelerometer Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "gyroscopeEnabled",
            label: "Gyroscope Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "magnetometerEnabled",
            label: "Magnetometer Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "humidityEnabled",
            label: "Humidity Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "humidityNotificationInterval",
            label: "Humidity Notification Interval (ms)",
            type: {
                id: "integer"
            },
            defaultValue: 60000
        }, {
            id: "luxometerEnabled",
            label: "Luxometer Enabled",
            type: {
                id: "boolean"
            },
            defaultValue: true
        }, {
            id: "luxometerNotificationInterval",
            label: "Luxometer Notification Interval (ms)",
            type: {
                id: "integer"
            },
            defaultValue: 60000
        }]
    },
    create: function (device) {
        return new TISensorTag();
    },
    discovery: function (options) {
        var discovery = new TISensorTagDiscovery();

        discovery.options = options;

        return discovery;
    }
};

var q = require('q');
var SensorTag = require("sensortag");

function TISensorTagDiscovery() {
    /**
     *
     * @param options
     */
    TISensorTagDiscovery.prototype.start = function () {
        if (this.node.isSimulated()) {
        } else {
            SensorTag.discover(function (sensorTag) {
                var tiSensorTag = new TISensorTag();

                tiSensorTag.sensorTag = sensorTag;
                tiSensorTag.uuid = sensorTag.uuid;
            });
        }
    };

    /**
     *
     * @param options
     */
    TISensorTagDiscovery.prototype.stop = function () {
    };
}

/**
 *
 */
function TISensorTag() {
    /**
     *
     */
    TISensorTag.prototype.start = function () {
        var deferred = q.defer();

        this.state = {
            acceleration: {x: null, y: null, z: null},
            barometricPressure: null,
            gyroscopicPropulsion: {x: null, y: null, z: null},
            humidity: null,
            irTemperature: null,
            ambientTemperature: null,
            magneticFieldStrength: {x: null, y: null, z: null},
            luminousIntensity: null
        };

        if (this.sensorTag) {
            this.connect();

            deferred.resolve();
        }
        else {
            if (!this.isSimulated()) {
                if (!SensorTag) {
                    SensorTag = require("sensortag");
                }

                this.scan();

                deferred.resolve();
            } else {
                setInterval(function () {
                    this.state = {
                        acceleration: {
                            x: Math.floor((Math.random() * 10)),
                            y: Math.floor((Math.random() * 10)),
                            z: Math.floor((Math.random() * 10))
                        },
                        barometricPressure: 1000 + Math.floor((Math.random() * 200)),
                        gyroscopicPropulsion: {
                            x: Math.floor((Math.random() * 50)),
                            y: Math.floor((Math.random() * 50)),
                            z: Math.floor((Math.random() * 50))
                        },
                        humidity: 60 + Math.floor((Math.random() * 10)),
                        irTemperature: 20 + Math.floor((Math.random() * 10)),
                        ambientTemperature: 20 + Math.floor((Math.random() * 10)),
                        magneticFieldStrength: {
                            x: Math.floor((Math.random() * 10)),
                            y: Math.floor((Math.random() * 10)),
                            z: Math.floor((Math.random() * 10))
                        },
                        luminousIntensity: 1500 + Math.floor((Math.random() * 10))
                    };

                    this.publishStateChange();
                }.bind(this), 1000);

                deferred.resolve();
            }
        }

        return deferred.promise;
    };

    /**
     *
     */
    TISensorTag.prototype.scan = function () {
        console.log("\tScanning started.");

        SensorTag.discover(function (sensorTag) {
            if (sensorTag.uuid === this.configuration.uuid) {
                console.log("\nMatching Tag found.");

                this.sensorTag = sensorTag;

                this.sensorTag.on('disconnect', function () {
                    console.log('\nDisconnected.');
                    this.scan();
                }.bind(this));

                this.connect();
            }
        }.bind(this));
    };

    /**
     *
     */
    TISensorTag.prototype.connect = function () {
        this.sensorTag.connectAndSetUp(function () {
            this.sensorTag.readDeviceName(function (error, deviceName) {
                console.log('\tdevice name = ' + deviceName);
            }.bind(this));
            this.sensorTag.readManufacturerName(function (error, manufacturerName) {
                console.log('\tmanufacturer name = ' + manufacturerName);
            }.bind(this));
            this.sensorTag.readSystemId(function (error, systemId) {
                console.log('\tsystem ID = ' + systemId);
            }.bind(this));
            this.sensorTag.readSerialNumber(function (error, serialNumber) {
                console.log('\tserial number = ' + serialNumber);
            }.bind(this));

            // Temperatures

            this.sensorTag.enableIrTemperature(function () {
                this.sensorTag.on('irTemperatureChange', function (objectTemperature, ambientTemperature) {
                    this.state.objectTemperatur = objectTemperature.toFixed(1);
                    this.state.ambientTemperatur = ambientTemperature.toFixed(1);

                    this.publishStateChange();
                }.bind(this));
            }.bind(this));

            // Accelerometer

            if (this.configuration.accelerometerEnabled) {
                this.sensorTag.enableAccelerometer(function () {
                    this.sensorTag.on("accelerometerChange", function (x, y, z) {
                        this.state.acceleration.x = x.toFixed(1);
                        this.state.acceleration.y = y.toFixed(1);
                        this.state.acceleration.z = z.toFixed(1);

                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Gyroscope

            if (this.configuration.gyroscopeEnabled) {
                this.sensorTag.enableGyroscope(function () {
                    this.sensorTag.on("gyroscopeChange", function (x, y, z) {
                        this.state.gyroscopicPropulsion.x = x.toFixed(1);
                        this.state.gyroscopicPropulsion.y = y.toFixed(1);
                        this.state.gyroscopicPropulsion.z = z.toFixed(1);

                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Magnetometer

            if (this.configuration.magnetometerEnabled) {
                this.sensorTag.enableMagnetometer(function () {
                    this.sensorTag.on("magnetometerChange", function (x, y, z) {
                        this.state.magneticFieldStrength.x = x.toFixed(1);
                        this.state.magneticFieldStrength.y = y.toFixed(1);
                        this.state.magneticFieldStrength.z = z.toFixed(1);

                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Humidity

            if (this.configuration.humidityEnabled) {
                this.sensorTag.enableHumidity(function () {
                    if (this.configuration.humidityNotificationInterval > 0) {
                        this.sensorTag.setHumidityPeriod(this.configuration.humidityNotificationInterval, function (error) {
                            this.sensorTag.notifyHumidity(function (error, humidity) {
                                if (humidity) {
                                    this.state.humidity = humidity.toFixed(1);
                                    this.publishStateChange();
                                }
                            }.bind(this));
                        }.bind(this));
                    }

                    this.sensorTag.on("humidityChange", function (humidity) {
                        this.state.humidity = humidity.toFixed(1);
                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Barometric Pressure

            if (this.configuration.barometricPressureEnabled) {
                this.sensorTag.enableBarometricPressure(function () {
                    if (this.configuration.barometricPressureNotificationInterval > 0) {
                        this.sensorTag.setBarometricPressurePeriod(this.configuration.barometricPressureNotificationInterval, function (error) {
                            this.sensorTag.notifyBarometricPressure(function (error, barometricPressure) {
                                if (barometricPressure) {
                                    this.state.barometricPressure = barometricPressure.toFixed(1);

                                    this.publishStateChange();
                                }
                            }.bind(this));
                        }.bind(this));
                    }
                    this.sensorTag.on("barometricChange", function (barometricPressure) {
                        this.state.barometricPressure = barometricPressure.toFixed(1);
                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Luxometer

            if (this.sensorTag.type != "cc2540" && this.configuration.luxometerEnabled) {
                this.sensorTag.enableLuxometer(function () {
                    if (this.configuration.luxometerNotificationInterval > 0) {
                        this.sensorTag.setLuxometerPeriod(this.configuration.luxometerNotificationInterval, function (error) {
                            this.sensorTag.notifyLuxometer(function (error, luminousIntensity) {
                                this.state.luminousIntensity = luminousIntensity.toFixed(1);
                                this.publishStateChange();
                            }.bind(this));
                        }.bind(this));
                    }

                    this.sensorTag.on("luxometerChange", function (luminousIntensity) {
                        this.state.luminousIntensity = luminousIntensity.toFixed(1);
                        this.publishStateChange();
                    }.bind(this))
                }.bind(this));
            }

            // Simple Keys

            this.sensorTag.on("simpleKeyChange", function (left, right) {
                console.log("Keys", left, right);

                if (left) {
                    this.publishEvent("left");
                }

                if (right) {
                    this.publishEvent("right");
                }
            }.bind(this));
        }.bind(this));
    };

    /**
     *
     */
    TISensorTag.prototype.scalarDeviation = function (value, lastValue) {
        return Math.abs(lastValue - value) / lastValue;
    };

    /**
     *
     */
    TISensorTag.prototype.vectorDeviation = function (value, lastValue) {
        var percentage = Math.sqrt(Math.pow(lastValue.x - value.x, 2) + Math.pow(lastValue.y - value.y, 2) + Math.pow(lastValue.z - value.z, 2)) /
            Math.sqrt(Math.pow(lastValue.x, 2) + Math.pow(lastValue.y, 2) + Math.pow(lastValue.z, 2));

        return percentage;
    };

    /**
     *
     */
    TISensorTag.prototype.setState = function (state) {
        this.state = state;
    };

    /**
     *
     */
    TISensorTag.prototype.getState = function () {
        return this.state;
    };
}
<|endoftext|>