Thermostat
Â
Description
This model will show the actual temperature and set point of a vav. Â It will change colors based off if it is heating or cooling, and will show occ or unocc. Â The gear will pull up the actions, and the setpoint can be changed with the plus and minus buttons.
Completed Model (Basic)
Download:Â Thermostat.zip
Video
Example:Â
Ractive Code
Template
<div class="s-topImg"> <img class="s-img" src="/finGetFile/demo?fileRef=@20ba1036-2c3f2e99"> <label class="view-superman-label s-imgTextB">{{myTemp.tz}}</label> <label class="view-superman-label s-imgTextW">{{myTemp.tz}}</label> </div> <div class="view-superman-label s-nameLabel"> <label class="s-equipName">{{myTemp.equipRefDis}}</label> </div> <div class="s-actual {{#if backColor.curVal}}Heating{{else}}Cooling{{/if}}"> {{#myTemp}} <div> <label class="icon-checkmark {{#if checkMark.writeVal}}s-checkTrue{{else}}s-checkFalse{{/if}}"></label> <label class="view-superman-label s-checkLabel">{{#if checkMark.writeVal}}Occ{{else}}Unocc{{/if}}</label> <label class="view-superman-label s-unit">{{unit}}</label></div> <div align="center"><br><br> <label class="view-superman-label s-titleA">Actual Room Temperature</label><br> <label class="view-superman-label s-tempA">  {{curVal.toFixed(1)}}º </label><br> </div> <div><label class="{{#if checkMark.writeVal}}wi-day-sunny{{else}}wi-night-clear{{/if}} s-sun"></label> <label class="s-fire {{#if backColor.curVal}}wi-fire{{else}}wi-snowflake-cold{{/if}}"></label></div> {{/myTemp}} </div> <div class="s-barDiv"> <div class="view-superman-label s-bar {{#if backColor.curVal}}Heating1{{else}}Cooling1{{/if}}" style="width: {{#if myTemp.maxVal}}{{myTemp.curVal/myTemp.maxVal*100}}{{else}}{{myTemp.curVal}}{{/if}}%;"></div> <div class="view-superman-label s-arrowA" style="left: {{#if myTemp.maxVal}}{{mySetPoint.curVal/ myTemp.maxVal*100}}{{else}}{{mySetPoint.curVal}}{{/if}}%;"></div> <div class="view-superman-label s-arrowSP" style="left: {{#if myTemp.maxVal}}{{myTemp.curVal/myTemp.maxVal*100}}{{else}}{{myTemp.curVal}}{{/if}}%;"></div> </div> <div class="s-setP"> <div align="center"> {{#mySetPoint}} <div class="icon-gear s-gear" on-click="actions"></div> <div class="view-superman-label s-circle"><div class="s-circleValue">{{writeLevel}}</div></div> <label class="view-superman-label s-circleLabel">Priority</label> <br><br> <label class="view-superman-label s-titleSP">Room Temperature Setpoint</label><br> <br> <div class="s-setDiv" align="center"> <button class="view-superman-label s-button" on-click="decrement"> <div class="icon-minus s-minus"></div> </button> <label class="view-superman-label s-tempSP"> {{curVal}}º </label> <button class="view-superman-label s-button" on-click="increment"> <div class="icon-plus s-plus"></div> </button> </div> {{/mySetPoint}} </div> </div>
This sets up the model
Model
{ data: { myTemp: null, mySetPoint: null, backColor: null, checkMark: null } }
Style
.s-topImg{ height: 20%; background-color: #e0e0e0; } .s-img{ width: 100%; height: 100%; } .s-imgTextW{ position:fixed; right:5%; bottom:85%; font-size: 400%; color: #fff; } .s-imgTextB{ position:fixed; right:5.25%; bottom:84.75%; font-size: 400%; color: #000; } .s-nameLabel{ background-color: #333; color: #fff; text-align: center; font-size: 25px; height: 10%; padding-top: 15px; } .s-arrowLeft{ float: left; margin-top: -3px; color: #fff; font-size: 350%; cursor: pointer; } .s-arrowRight{ float: right; margin-top: -3px; color: #fff; font-size: 350%; cursor: pointer; } .s-equipName{ margin-top: 15px; font-size: 225%; } .s-actual{ padding: 20px; height: 32%; } .s-checkTrue{ font-size: 3em; color: #6cc487; text-align: left; } .s-checkFalse{ font-size: 3em; color: #afafb0; opacity: 0.5; text-align: left; } .s-checkLabel{ color: #fff; position:fixed; right:92.4%; bottom:62.5%; } .s-unit{ font-size: 3em; color: #fff; float: right; } .s-titleA{ color: #fff; font-size: 350%; } .s-tempA{ font-size: 1000%; color:#fff; } .s-sun{ font-size: 3em; color: #fff; /*float: right;*/ position:fixed; right:92%; bottom:39%; } .s-fire{ font-size: 3em; color: #fff; position:fixed; right:3%; bottom:39%; } .s-barDiv{ height: 5%; background: #CFD8DC; margin: 0 auto; position: relative; } .s-bar{ height: 100%; position:absolute; } .s-arrowA{ width: .3%; position: relative; background: #000; height: 100%; } .s-arrowA:after { content: ''; display: block; border: 7px transparent solid; border-bottom-color: #000; top: 96%; left: -6px; position: absolute; } .s-arrowSP{ bottom: 100%; width: .3%; position: relative; background: #fff; height: 100%; } .s-arrowSP:before { content: ''; display: block; bottom: 101%; left: -6px; position: absolute; width: 0; height: 0; border-left: 7px solid transparent; border-right: 7px solid transparent; border-top: 7px solid #fff; } .s-setP{ background-color: #e6e6e6; padding: 20px; height: 33%; } .s-titleSP{ color: #000; font-size: 350%; } .s-gear{ font-size: 3em; color: #000; text-align: left; cursor: pointer; } .s-circle{ background-color: #47a3da; height: 42px; width: 42px; border-radius: 50%; color: #fff; position:fixed; right:2.3%; bottom:27.5%; } .s-circleValue{ margin-top:6px; font-size: 2em; } .s-circleLabel{ color: #afafb0; opacity: 0.8; position:fixed; right:2%; bottom:25.5%; } .s-setDiv{ display: flex; justify-content: center; align-items: center; } .s-button{ background-color: #dadada; border: none; height: 120px; width: 120px; border-radius: 50%; cursor: pointer; } .s-tempSP{ font-size: 1000%; color:#000; } .s-minus{ color: #3488b2; font-size: 4em; margin-top:4px; margin-left: 1px; } .s-plus{ color: #d40000; font-size: 4em; margin-top:4px; margin-left: 1px; } .Cooling{ background: #5e98e0; background: -webkit-linear-gradient(left bottom, #8fcffa, #5e98e0, #5d42b0); background: -moz-linear-gradient(top right, #8fcffa, #5e98e0, #5d42b0); background: linear-gradient(to top right, #8fcffa, #5e98e0, #5d42b0); width: 100%; } .Heating{ background: #5e98e0; background: -webkit-linear-gradient(left bottom, #e5b356, #cf7b4c, #a83128); background: -moz-linear-gradient(top right, #e5b356, #cf7b4c, #a83128); background: linear-gradient(to top right, #e5b356, #cf7b4c, #a83128); width: 100%; } .Off{ background-color: #e0e0e0; width: 100%; } .Heating1{ background-color: #b8443f; } .Cooling1{ background-color: #5d8eca; } .Off1{ background-color: #47a3da; }
This is the css to style the component
INIT
var self = this.ractive; this.ractive.fire("obtainData"); var count = 0; this.ractive.on("increment", function(event){ var point = this.get('mySetPoint'); var val = parseFloat(point.curVal); val += 1; if (val >= 84) val=84; if (val <= 0) val=0; finstack.eval('readById(' +point.id+ ').pointOverride(' +val+ ')').then(function(data) { if (data && data.result) { if (data.result.isErrorGrid) { console.error("Error occurred while updating value"); return; } self.set('mySetPoint.curVal', val); } }, function(err) { console.error("Error occurred while updating...", err); }); }); this.ractive.on("decrement", function(event) { var point = this.get('mySetPoint'); var val = parseFloat(point.curVal); val -= 1; if (val >= 84) val=84; if (val <= 0) val=0; finstack.eval('readById(' +point.id+ ').pointOverride(' +val+ ')').then(function(data) { if (data && data.result) { if (data.result.isErrorGrid) { console.error("Error occurred while updating value"); return; } self.set('mySetPoint.curVal', val); } }, function(err) { console.error("Error occurred while updating...", err); }); }); this.ractive.on("actions", function(event) { var item = this.get(event.keypath); var mainWin = window.parent; try { mainWin.app.ShowActionsFor (item.id); } catch (err) {console.error(err)} });
Program
var roomT = this; var roomSP = this; var color = this; var occColor = this; var target = query("targetPoint"); finstack.eval('readAll((navName=="Room Temp") and floorRef=='+target.floorRef+' and siteRef=='+target.siteRef+' and equipRef=='+target.pointId+')', function(data){ roomT.myTemp=data.result.toObj()[0]; }); finstack.eval('readAll((navName=="Room Setpoint") and floorRef=='+target.floorRef+' and siteRef=='+target.siteRef+' and equipRef=='+target.pointId+')', function(data){ roomSP.mySetPoint=data.result.toObj()[0]; }); finstack.eval('readAll((navName=="OccHeat") and floorRef=='+target.floorRef+' and siteRef=='+target.siteRef+' and equipRef=='+target.pointId+')', function(data){ color.backColor=data.result.toObj()[0]; }); finstack.eval('readAll((navName=="Occ Mode") and floorRef=='+target.floorRef+' and siteRef=='+target.siteRef+' and equipRef=='+target.pointId+')', function(data){ occColor.checkMark=data.result.toObj()[0]; });
This is your program. Â It sets the query for the model. Â If your point's navName are not called Room Temp, Room Setpoint, OccHeat, and Occ Mode, they will have to be change accordingly on lines 6, 10, 14, and 18 (navName==" Â Â ")
How To Make your Own
- Size your graphics builder to 750X1046 and turn on scale to fit
 - Bring Ractive out from components on the left side menu
- Under properties change the position so x and y are both 0, and set the width and height both to 100%
- Then open the ractive editor, and copy and paste from the Ractive Code given above for template, model, style, and init
- Next add a tag on your Ractive component and add a new program
- Copy and paste the above code for program into the main part
- Name your program, and set the program target filter to stackRactive
- Top right of program editor, click the three dots, and select variables
- Click the gear that appears as you hover over this
- turn Invokes the Function on and change the dropdown to Custom Event
- Type in obtainData in the line below and click the gray save
Click the blue save for your program
Adding a Timer
- Drag out a timer from components and add the tag timer
- Edit your program by clicking the gear
- Click the three dots in the top right corner and add a new variable
- You can call it whatever you want in our case we named it timer
- Next set it to the timer, and have it invoke the function, and set it to the custom event timer
- Click the gray save, then the blue save and your done!
- Save and you're done!