Module development

Posted on
  • While developing a module, it is convenient in early stages to have all code in one and the same file, that is:

    • module code
    • some test code
    • application (example) code

    For a module example, I want to have a module that

    • retrieves a temperature (polls)
      • from a given DS18B20 sensor
      • on given intervals
    • holds on to the sensed temperature
    • has a name for the temperature
    • returns name and degrees in desired unit (Celsius or Fahrenheit)

    This is good enough for now, because:

    The focus of this conversation is less on the module and its functions but more so on the development process within the Espruino Eco System - IDE, Project, Sandbox, Module Compiler (js minifier), etc.

    Subsequent post will walk you through the steps to build a module for yourself... and may be for others too.

  • 1. For a first step, we develop the module code and usage in single file TemperatureDevTest.js:

    The code below is working and covers basically the above requirements for the module:

    // TemperatureDevTest.js
    
    // 'class' (Prototype definition)
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred === "F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
        _this.sensor.getTemp(function(t) {
            _this.t = t;
          });
      }, this.interval, this);
    };
    Temperature.prototype.getTemp = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u 
          = (typeof unit === "undefined") ? this.preferred
          : (unit === "F"               ) ? "F"
          :                                 "C"
          ;
      var d = (u === "F")
          ? (this.t * 1.8 + 32) + " Fahrenheit"
          : this.t + " Celsius";
      return d;
    };
    
    
    // usage
    
    // setup oneWire
    var oneWire = new OneWire(B8);
    
    // setup 1st temperature sensor ts1
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    
    
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    
    // get temp in preferred and ad-hoc specified units 
    console.log(ts1.getTemp());
    console.log(ts1.getTemp("C"));
    
    },6000);
    

    The output - in the console - is as expected (code unrelated: unusually hot... a heat wave... usually it is around 50 F or even less this early in the morning...)

     _____                 _
    |   __|___ ___ ___ _ _|_|___ ___
    |   __|_ -| . |  _| | | |   | . |
    |_____|___|  _|_| |___|_|_|_|___|
              |_| http://espruino.com
     1v94 Copyright 2016 G.Williams
    >
    =undefined
    83.1875 Fahrenheit
    28.4375 Celsius
    >
    
  • 2. For the second step, we want to use the code like a module.

    *** EDIT No 'hands-on' for this 2nd step as outlined in posts #3 thru #7. Following it in thoughts and understanding the concepts is sufficient. Hands-on is again asked for post #8 and beyond. ***

    To use the code like a module, in other words, use the require(moduleName), we have to shove the code as module into the Modules cache: see [espruino.com/Reference#Modules]http://www.espruino.com/Reference#Module­s). The Modules is a global JavaScript object that holds on to the uploaded modules. The modules are uploaded, stored and retrieved by the 'moduleName' (also called 'moduleId'), which is at the same time the file name for local and official modules, and the url for a module from anywhere of the web.

    Usually, the upload retrieves the module from either the local sandbox, the official espruino.com/modules library of the Web, or any other place of the Web by supplying the full url as 'moduleName'. How code and modules are loaded is touched on in the conversation about simple explanation how to save code that espruino run on start?.

    The same means that upload uses to upload modules to the board are available to us in either the console or the already uploaded to the board. The Modules as global JavaScript object has behavior - methods / functions - which we can use to store a module. The method looks like this in the complete JavaScript expression: Modules..addCached(id, sourcecode), where id is the moduleName as string and sourcecode is the complete source code as a single string.

    To make the code work like a module (on retrieval or add and retrieval), we must add exports = objectToBeExported (or ...toBeExposed) at the end of the the code. The objectToBeExported is for most modules a simple object with one method / function connect, which uses module code to connect to and sometimes initialize the device the module is all about. The nice thing about this export / expose approach is to intentionally make to the application available only what is needed and hide and protect other things. Hiding thins also avoids naming conflicts between application and modules and among modules that would make use and reuse of modules a very difficult not to say impossible task.

    Looking at some existing modules, you find that export does this - for example, for the DS18B20 Temperature Sensor:

    ...
    exports.connect = function(oneWire, device) {
        return new DS18B20(oneWire, device);
    

    The exports object is already there and sometimes the module adds to the object the properties / methods / functions it wants to export/expose or it set the exports object all together to point to a new object. In 'DS18B20' case, the .connect(...) method is added which uses the particular module code for implementation. In our 'class' / prototype case, we make the 'exports' point to the 'class' / prototype function, which is the constructor function that we will use in the application with new:

    ...
    exports = Temperature;
    

    With the module code now complete, we have to feed it into the Modules cache as a single string. There are multiple ways to do that as described in conversation about Module creation at runtime:

    • most obvious is to make each line of the source a string and concatenate them all...
    • use ES6 multi-line strings that are supported by Espruino.

    Making the source code lines all string and concatenate them is though quite some work and will need more work when further down the development process the will be stored as separate module file. Therefore we will use the ES 6 multi-line string to achieve the change very quickly:

    • before the first line of module code we add Modules.addCached("Temperature",backTick­
    • after the last line we add backTick);

    ...where 'backTick' is the backwards-looking single quote (`), also called (in French) 'accent-grave'.

    Putting backTicks around multiple lines makes JavaScript to look at it these a single string ignoring the line ends (CR / CRLF / LF). Using this string in the Modules.addCached(...) methods as parameter, Espruino does not anymore look at it as code that is to be processed (compiled, interpreted, and executed). Latter is a major shift in regard how and when module code is looked at as code. So far, it was looked at as code right on arrival at Espruino on upload. backTicked, it is looked at as plain string on arrival on the board and is looked at as code and processed as such (compiled) when stored in Modules cache.

    Note: When the module code is very large and so the source as string will be too, you may ran out of memory... But to that, there is a solution as shown in the next post.

    Last change is in the application part where we now have to retrieve the the Temperature 'class'/prototype definition as module instead of direct reference the already available constructor function. Since - for what ever reason ... = new require("Temperature")(...) construct is not working in Espruino, we add an extra line just before the line with ...new...': var Temperature = require("Temperature");.

    Since Temperature is a 'class'/prototype, it is appropriate to name/spell it so. If it would be another module, for exmple the one for the 'DS18B20' temperature sensor, we would name it lower case beginning like var ds18b20Mod = require("DS18B20"); and later use var tempSensor = ds18b20Mod.connect(...); to ('create' a sensor and) connect to it.

    Even though we are done with 'modularizing', it is not good enough: Since we do not go through the usual upload process that parses any required module for nested 'requireds', our module will fail on usage. Why? Answer: From where should Espruino know that it should have retrieved the module(s) referenced in the module as well?

    Solution to the missing nested module 'DS18B20' is to upload the referenced module(s) 'upfront' - if known at that time - or retrieved and added to the cache 'now' dynamically as well, either from included code or code read from 'somewhere', such as SD Card... or the Web.

    For our simple example - and because we know what will be used, we add this require("DS18B20");" to the code... almost as a dummy,... but because it is in the active, uploaded code (and not in a string), it is detected at the beginning of the upload and retrieved and uploaded by the uploader (...may be @Gordon may change this and let pass strings in the code as well through the recursive module detector and uploader. Until then, we just do it in our application code... and it will not hurt even when the function becomes available). It does not really matter where we place thisrequire("DS18B20");` - before of after the dynamically loading of the module or somewhere else. Useful is to put it close, and I decided it to put it just before. I will have to remove it when the module will be completed and statically available

    The final code looks like below... where the Temperature 'class'/prototype definition is handled and used as a module:

    // TemperatureDevTest2.js
    
    require("DS18B20"); // used by the dynamically loaded module
    Modules.addCached("Temperature",`
    // Temperature.js
    // 'class' (Prototype definition)
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred==="F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
          _this.sensor.getTemp(function(t) {
          _this.t = t;
        });
      }, this.interval, this);
    };
    Temperature.prototype.getTemp = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u = ((typeof unit !== "undefined") && (unit === "F")) ? "F" : "C";
      var d = (u === "F")
        ? (this.t * 1.8) + " Fahrenheit"
        : this.t + " Celsius";
      return d;
    };
    
    exports = Temperature;
    `);
    
    
    // usage
    
    // setup oneWire
    var oneWire = new OneWire(B8);
    
    // setup 1st temperature sensor ts1
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    
    
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    
    // get temp in preferred unit 
    console.log(ts1.getTemp());
    
    },6000);
    

    It works as expected and shows in the console:

     _____                 _
    |   __|___ ___ ___ _ _|_|___ ___
    |   __|_ -| . |  _| | | |   | . |
    |_____|___|  _|_| |___|_|_|_|___|
              |_| http://espruino.com
     1v94 Copyright 2016 G.Williams
    >
    =undefined
    31.375 Celsius
    > 
    

    Pretty hot...is it! - I mean also literally...

  • As mentioned in the previous post, the string containing a complete module can be pretty big and could lead to run out of memory. Therefore the question:

    How can a module be broken up into small(er) pieces and composed at runtime from such pieces.

    In order to have the a piece of code working as a module, it is good enough to have a 'hock object' as the first or core component in the Modules cache to which more components can 'be attached' to. To attache components to a module core component, the module has to be required from the cache and then the components can 'be attached' to it. After all, the module - in this case the 'class'/prototype definition - is just a function object - one and the same whether in the cache or in the application code.

    Since the constructor function is such a first and core component, let's try to attache a the .getTemp() as a component.

    Intentionally, the module was retrieved into a temporary variable tempTemp - line 37 - to prove that the module is the very same object that is later retrieved into the original variable Temperature - line 57 - and includes now the complete Temperature 'class'/prototype definition.

    The split up module code into core component - lines 4..34 - and other component(s) - lines 49/41..48 - and attaching the other component(s), such as a method method - line 40 - represents composing a complete module from components component by component. The code for it looks like this:

    // TemperatureDevTest2.js
    
    require("DS18B20"); // used by the dynamically loaded module
    Modules.addCached("Temperature",`
    // Temperature.js
    // 'class' (Prototype definition)
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred==="F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
          _this.sensor.getTemp(function(t) {
          _this.t = t;
        });
      }, this.interval, this);
    };
    
    exports = Temperature;
    `);
    
    // require the Temperature module into a temporary tempTemp var:
    var tempTemp = require("Temperature");
    
    // attach the .getTemp() method
    tempTemp.prototype.getTemp = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u = ((typeof unit !== "undefined") && (unit === "F")) ? "F" : "C";
      var d = (u === "F")
        ? (this.t * 1.8) + " Fahrenheit"
        : this.t + " Celsius";
      return d;
    };
    
    
    // usage
    
    // setup oneWire
    var oneWire = new OneWire(B8);
    
    // setup 1st temperature sensor ts1
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    
    
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    
    // get temp in preferred unit 
    console.log(ts1.getTemp());
    
    },6000);
    

    There is one comment to make: if the to-attach module component is retrieved over the network or read from a storage it is retrieved as a string and not as an object... but that is no issue what so ever... we just 'ab-use' the Modules.addCached(...) and require(...) infrastructure as a stepping stone:

    • add the to-attach component to the Modules cache as a module with Modules.addCached(...) - lines 36..49.
    • retrieve the to-attach component as module from the Modules cache with require() - line 55.
    • attach it to the core module retrieved from the Modules cache as done before - line 55.

    The code with all module components as strings looks then like:

    // TemperatureDevTest2.js
    
    require("DS18B20"); // used by the dynamically loaded module
    Modules.addCached("Temperature",`
    // Temperature.js
    // 'class' (Prototype definition)
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred==="F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
          _this.sensor.getTemp(function(t) {
          _this.t = t;
        });
      }, this.interval, this);
    };
    
    exports = Temperature;
    `);
    
    // add .getTemp() method as moduleComponent to the Modules cache
    Modules.addCached("moduleComponent",`
    var moduleComponent = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u = ((typeof unit !== "undefined") && (unit === "F")) ? "F" : "C";
      var d = (u === "F")
        ? (this.t * 1.8) + " Fahrenheit"
        : this.t + " Celsius";
      return d;
    };
    
    exports = moduleComponent;
    `);
    
    // require the Temperature module into a temporary tempTemp var:
    var tempTemp = require("Temperature");
    
    // require and attach the .getTemp() method as module component
    tempTemp.prototype.getTemp = require("moduleComponent");
    
    // usage
    
    // setup oneWire
    var oneWire = new OneWire(B8);
    
    // setup 1st temperature sensor ts1
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    
    
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    
    // get temp in preferred unit 
    console.log(ts1.getTemp());
    
    },6000);
    

    ...and works - and we get two (2) warnings about module not found on upload as expected... of course it runs... no magic... just JavaScript brilliantly and to it's true nature implemented by @Gordon.

  • Two final challenges remain to resolve - even though they are not part of the overall topic of this conversation:

    1. See something like this at runtime where the core of the application - internet connectivity - is uploaded to the board and the rest of the application is pulled in dynamically over the Web in the start-up of the application.

    2. See an application at runtime replacing a module on predefined expiration or server notification over the Web by shutting down the module, replacing it with the new, updated version over the Web, and restarting it. Depending on the dependencies, it may be easier to just restart the whole application, and the solution of challenge 1. solves the 'logical' challenge 2.

    But what we have shown so far is how we can develop even large module(s) within the same source file as the application through the module(s)'s early stages.

    Next post returns back to the topic and focus of this conversion: Module development(process).

  • Looks good - I'd say if you're running into out of memory errors, you should probably just do what is described in the first step - without using Modules.addCached.

    Pulling modules over the internet is very possible - it's actually quite easy (download as a string, and use Modules.addCached). The problem is that it needs to be asynchronous, and require is synchronous - so it can't be built in as part of the standard require function.

    For replacing a module, you'd have to have a carefully designed module that could fully unload itself - and that you kept no references to. However if that is done then yes, replacing it on the fly could definitely be done.

  • The problem is that it needs to be asynchronous, and require is synchronous

    ...with that comment we come full circle with #4 and #5 of the conversation about How to create a module that is a 'Class' - aka a function usable with new - or: How to make require() return a function and not an object.

    A nice historical event...

    At that time you posted '...That one's definitely not in my plans at all I'm afraid!'. With promises now implemented, I'm not so sure this statement of your's still stands firm... ;-) ---

    *** Espruino is now closer to the require.js / AMD as it ever was... and kind of an M2M Browser Eco System vs. a Web Browser... ***

    (Just a little bit food for thought: enabling require to detect the invocation pattern/method signature - single string vs. array - would allow the async approach, of course it also requires some flanking support actions, like a way to define how and where to pull the modules asynchronously. This food for thought is though a rabbit trail of this conversation and will have to be in its own conversation).

  • In the related conversation about Module creation at runtime I learned about a superior solution for step 2:

    Modules.addCached(...) accepts the module code also as a function, something like this:

    Modules.addCached("MyObject", function(){
      // MyObject.js
      // Code of MyObject module implementing MyObject class/prototype.
      var MyObject = function(instanceName) { // constructor
        this.instanceName = instanceName;
        this.creationTimestamp = new Date().getTime();
      }
      MyObject.prototype.getInfo() {
        return this.instanceName + " created at " + this.creationTimestamp;
     }
     exports = MyObject;
    });
    

    Lines 2..11 represent the exact code that will become the 'outfactored' module. Keeping the module code as 'active' code in the wrapping, anonymous function passed into .addCached(..) keeps the code visible for the Espruino Web IDE editor and with that we get syntax coloring and code the Espruino specific code completion and easier debug-ability. With code as string none of these feature are available to the developer.

    The final code using this more useful approach looks then like this:

    // TemperatureDevTest2.js
    
    require("DS18B20"); // used by the dynamically loaded module
    Modules.addCached("Temperature", function() {
    // Temperature.js
    // 'class' (Prototype definition)
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred==="F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
          _this.sensor.getTemp(function(t) {
          _this.t = t;
        });
      }, this.interval, this);
    };
    Temperature.prototype.getTemp = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u = ((typeof unit !== "undefined") && (unit === "F")) ? "F" : "C";
      var d = (u === "F")
        ? (this.t * 1.8) + " Fahrenheit"
        : this.t + " Celsius";
      return d;
    };
    
    exports = Temperature;
    });
    
    
    // usage
    
    // setup oneWire
    var oneWire = new OneWire(B8);
    
    // setup 1st temperature sensor ts1
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    
    
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    
    // get temp in preferred unit 
    console.log(ts1.getTemp());
    
    },6000);
    

    Lines 3..42 will become the - un-minified - source of the module file placed into the modules folder of the sandbox (or any other module repository).

  • 3. For the third step, we tidy up the module code with some (extra) documentation.

    It is very useful to include in the module code - as comment - some terse documentation about the usage of the module, see example in DS18B20 temperature sensor module. The embedded module documentation/information is at the beginning in block comment.

    The usage example is taken from current code. The code to be and to be used as a module -
    lines 5..65 - looks like this:

    // TemperatureDevTest2.js
    require("DS18B20"); // used by the dynamically loaded module
    Modules.addCached("Temperature", function() {
    
    /* Copyright (c) 2017 ... */
    /*
    Module to wrap application of DS18B20 temp sensor module in Temperature class
    
    ` ` `
    var oneWire = new OneWire(B8);
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    var temp = 0;
    setTimeout() { function() {
      var tempTemp = ts1.getTemp(); // get temperature,...
      if (tempTemp != temp) {       // ... if changed from last time,...
        temp = tempTemp;            // ... hold on to it and...
        console.log(new Date() + ": " + temp; // ...print it;...
      } }, 10000); // ...every ten seconds // ...do this every 10 seconds
    ` ` `
     */
    
    // Temperature 'class'/prototype definition
    var Temperature = function // module (class), for multiple instances
      ( name      // name hinting room / location of sensor\
      , oneWire   // one-wire; for example: new OneWire(B8);
      , addr      // address on the one-wire (required for multiples)
      , interval  // interval in milliseconds of measurements
      , preferred // optional, unit - "C" or "F" (default and not F is C)
      ) {
      // set givens
      this.name       = name;
      this.oneWire    = oneWire;
      this.addr       = addr;
      this.interval   = interval;
      this.preferred  = (preferred==="F") ? "F" : "C";
      this.enabled    = (typeof enabled === "undefined") || enabled;
      this.t = (this.preferred==="C") ? 0 : 32; // set current to 'frozen'
      this.intervalId = null; // later also used as indicator for enabled
      this.sensor     = null; // laster also used as indicatore for connected
      // get going
      this.sensor = require("DS18B20").connect(this.oneWire)­;
      this.intervalId = setInterval(function(_this) {
          _this.sensor.getTemp(function(t) {
          _this.t = t;
        });
      }, this.interval, this);
    };
    Temperature.prototype.getTemp = function
    ( unit // optional, unit "F" or "C", default "C"
    ) {
      var u = ((typeof unit !== "undefined") && (unit === "F")) ? "F" : "C";
      var d = (u === "F")
        ? (this.t * 1.8) + " Fahrenheit"
        : this.t + " Celsius";
      return d;
    };
    
    exports = Temperature;
    
    });
    
    // usage
    // setup oneWire
    var oneWire = new OneWire(B8);
    // setup 1st temperature sensor ts1
    var Temperature = require("Temperature");
    var ts1 = new Temperature
      ( "office" // name / location of temperatre sensor 1
      , oneWire
      , null     // addr on one-wire currently not implemented / used
      , 5000     // every 5 secs make a read (to keep it not booring)
      , "F"      // preferred unit is Fahrenheit
      );
    // for sample's sake, do everhthing deferred for more 
    // than 5 seconds in order to have value(s) to display
    setTimeout(function(){
    // get temp in preferred unit 
    console.log(ts1.getTemp());
    },6000);
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Module development

Posted by Avatar for allObjects @allObjects

Actions