-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathnorered.flow
1 lines (1 loc) · 41.2 KB
/
norered.flow
1
[{"id":"1e740be5.c8eab4","type":"ui_template","z":"a91a4693.aec638","group":"fc782db1.a0407","name":"Living Room","order":1,"width":"6","height":"6","format":"<div id=\"thermostat\"></div>\n\n<style>\n@import url(http://fonts.googleapis.com/css?family=Open+Sans:300);\n#thermostat {\n margin: 0 auto;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n.dial {\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.dial.away .dial__ico__leaf {\n visibility: hidden;\n}\n.dial.away .dial__lbl--target {\n visibility: hidden;\n}\n.dial.away .dial__lbl--target--half {\n visibility: hidden;\n}\n.dial.away .dial__lbl--away {\n opacity: 1;\n}\n.dial.away .dial__lbl--boost {\n opacity: 0;\n}\n.dial.boost .dial__ico__leaf {\n visibility: hidden;\n}\n.dial.boost .dial__lbl--target {\n visibility: hidden;\n}\n.dial.boost .dial__lbl--target--half {\n visibility: hidden;\n}\n.dial.boost .dial__lbl--away {\n opacity: 0;\n}\n.dial.boost .dial__lbl--boost {\n opacity: 1;\n}\n.dial .dial__shape {\n -webkit-transition: fill 0.5s;\n transition: fill 0.5s;\n}\n.dial__ico__leaf {\n fill: #13EB13;\n opacity: 0;\n -webkit-transition: opacity 0.5s;\n transition: opacity 0.5s;\n pointer-events: none;\n}\n.dial.has-leaf .dial__ico__leaf {\n display: block;\n opacity: 1;\n pointer-events: initial;\n}\n.dial__editableIndicator {\n fill: white;\n fill-rule: evenodd;\n opacity: 0;\n -webkit-transition: opacity 0.5s;\n transition: opacity 0.5s;\n}\n.dial--edit .dial__editableIndicator {\n opacity: 1;\n}\n.dial--state--off .dial__shape {\n fill: #3d3c3c;\n}\n.dial--state--heating .dial__shape {\n fill: #E36304;\n}\n.dial--state--cooling .dial__shape {\n fill: #007AF1;\n}\n.dial__ticks path {\n fill: rgba(255, 255, 255, 0.3);\n}\n.dial__ticks path.active {\n fill: rgba(255, 255, 255, 0.8);\n}\n.dial text {\n fill: white;\n text-anchor: middle;\n font-family: Helvetica, sans-serif;\n alignment-baseline: central;\n}\n.dial__lbl--target {\n font-size: 120px;\n font-weight: bold;\n}\n.dial__lbl--target--half {\n font-size: 40px;\n font-weight: bold;\n opacity: 0;\n -webkit-transition: opacity 0.1s;\n transition: opacity 0.1s;\n}\n.dial__lbl--target--half.shown {\n opacity: 1;\n -webkit-transition: opacity 0s;\n transition: opacity 0s;\n}\n.dial__lbl--ambient {\n font-size: 22px;\n font-weight: bold;\n}\n.dial__lbl--away {\n font-size: 72px;\n font-weight: bold;\n opacity: 0;\n pointer-events: none;\n}\n.dial__lbl--boost {\n font-size: 72px;\n font-weight: bold;\n opacity: 0;\n pointer-events: none;\n}\n#controls {\n font-family: Open Sans;\n background-color: rgba(255, 255, 255, 0.25);\n padding: 20px;\n border-radius: 5px;\n position: absolute;\n left: 50%;\n -webkit-transform: translatex(-50%);\n transform: translatex(-50%);\n margin-top: 20px;\n}\n#controls label {\n text-align: left;\n display: block;\n}\n#controls label span {\n display: inline-block;\n width: 200px;\n text-align: right;\n font-size: 0.8em;\n text-transform: uppercase;\n}\n#controls p {\n margin: 0;\n margin-bottom: 1em;\n padding-bottom: 1em;\n border-bottom: 2px solid #ccc;\n}\n</style>\n<script>\n var thermostatDial = (function() {\n\t\n\t/*\n\t * Utility functions\n\t */\n\t\n\t// Create an element with proper SVG namespace, optionally setting its attributes and appending it to another element\n\tfunction createSVGElement(tag,attributes,appendTo) {\n\t\tvar element = document.createElementNS('http://www.w3.org/2000/svg',tag);\n\t\tattr(element,attributes);\n\t\tif (appendTo) {\n\t\t\tappendTo.appendChild(element);\n\t\t}\n\t\treturn element;\n\t}\n\t\n\t// Set attributes for an element\n\tfunction attr(element,attrs) {\n\t\tfor (var i in attrs) {\n\t\t\telement.setAttribute(i,attrs[i]);\n\t\t}\n\t}\n\t\n\t// Rotate a cartesian point about given origin by X degrees\n\tfunction rotatePoint(point, angle, origin) {\n\t\tvar radians = angle * Math.PI/180;\n\t\tvar x = point[0]-origin[0];\n\t\tvar y = point[1]-origin[1];\n\t\tvar x1 = x*Math.cos(radians) - y*Math.sin(radians) + origin[0];\n\t\tvar y1 = x*Math.sin(radians) + y*Math.cos(radians) + origin[1];\n\t\treturn [x1,y1];\n\t}\n\t\n\t// Rotate an array of cartesian points about a given origin by X degrees\n\tfunction rotatePoints(points, angle, origin) {\n\t\treturn points.map(function(point) {\n\t\t\treturn rotatePoint(point, angle, origin);\n\t\t});\n\t}\n\t\n\t// Given an array of points, return an SVG path string representing the shape they define\n\tfunction pointsToPath(points) {\n\t\treturn points.map(function(point, iPoint) {\n\t\t\treturn (iPoint>0?'L':'M') + point[0] + ' ' + point[1];\n\t\t}).join(' ')+'Z';\n\t}\n\t\n\tfunction circleToPath(cx, cy, r) {\n\t\treturn [\n\t\t\t\"M\",cx,\",\",cy,\n\t\t\t\"m\",0-r,\",\",0,\n\t\t\t\"a\",r,\",\",r,0,1,\",\",0,r*2,\",\",0,\n\t\t\t\"a\",r,\",\",r,0,1,\",\",0,0-r*2,\",\",0,\n\t\t\t\"z\"\n\t\t].join(' ').replace(/\\s,\\s/g,\",\");\n\t}\n\t\n\tfunction donutPath(cx,cy,rOuter,rInner) {\n\t\treturn circleToPath(cx,cy,rOuter) + \" \" + circleToPath(cx,cy,rInner);\n\t}\n\t\n\t// Restrict a number to a min + max range\n\tfunction restrictToRange(val,min,max) {\n\t\tif (val < min) return min;\n\t\tif (val > max) return max;\n\t\treturn val;\n\t}\n\t\n\t// Round a number to the nearest 0.5\n\tfunction roundHalf(num) {\n\t\treturn Math.round(num*2)/2;\n\t}\n\t\n\tfunction setClass(el, className, state) {\n\t\tel.classList[state ? 'add' : 'remove'](className);\n\t}\n\t\n\t/*\n\t * The \"MEAT\"\n\t */\n\n\treturn function(targetElement, options) {\n\t\tvar self = this;\n\t\t\n\t\t/*\n\t\t * Options\n\t\t */\n\t\toptions = options || {};\n\t\toptions = {\n\t\t\tdiameter: options.diameter || 400,\n\t\t\tminValue: options.minValue || 10, // Minimum value for target temperature\n\t\t\tmaxValue: options.maxValue || 30, // Maximum value for target temperature\n\t\t\tnumTicks: options.numTicks || 200, // Number of tick lines to display around the dial\n\t\t\tonSetTargetTemperature: options.onSetTargetTemperature || function() {}, // Function called when new target temperature set by the dial\n\t\t};\n\t\t\n\t\t/*\n\t\t * Properties - calculated from options in many cases\n\t\t */\n\t\tvar properties = {\n\t\t\ttickDegrees: 300, // Degrees of the dial that should be covered in tick lines\n\t\t\trangeValue: options.maxValue - options.minValue,\n\t\t\tradius: options.diameter/2,\n\t\t\tticksOuterRadius: options.diameter / 30,\n\t\t\tticksInnerRadius: options.diameter / 8,\n\t\t\thvac_states: ['off', 'heating', 'cooling'],\n\t\t\tdragLockAxisDistance: 15,\n\t\t}\n\t\tproperties.lblAmbientPosition = [properties.radius, properties.ticksOuterRadius-(properties.ticksOuterRadius-properties.ticksInnerRadius)/2]\n\t\tproperties.offsetDegrees = 180-(360-properties.tickDegrees)/2;\n\t\t\n\t\t/*\n\t\t * Object state\n\t\t */\n\t\tvar state = {\n\t\t\ttarget_temperature: options.minValue,\n\t\t\tambient_temperature: options.minValue,\n\t\t\thvac_state: properties.hvac_states[0],\n\t\t\thas_leaf: false,\n\t\t\taway: false,\n\t\t\tboost: false\n\t\t};\n\t\t\n\t\t/*\n\t\t * Property getter / setters\n\t\t */\n\t\tObject.defineProperty(this,'target_temperature',{\n\t\t\tget: function() {\n\t\t\t\treturn state.target_temperature;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.target_temperature = restrictTargetTemperature(+val);\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'ambient_temperature',{\n\t\t\tget: function() {\n\t\t\t\treturn state.ambient_temperature;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.ambient_temperature = roundHalf(+val);\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'hvac_state',{\n\t\t\tget: function() {\n\t\t\t\treturn state.hvac_state;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tif (properties.hvac_states.indexOf(val)>=0) {\n\t\t\t\t\tstate.hvac_state = val;\n\t\t\t\t\trender();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'has_leaf',{\n\t\t\tget: function() {\n\t\t\t\treturn state.has_leaf;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.has_leaf = !!val;\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'away',{\n\t\t\tget: function() {\n\t\t\t\treturn state.away;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.away = !!val;\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'boost',{\n\t\t\tget: function() {\n\t\t\t\treturn state.boost;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.boost = !!val;\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\t\t\t\n\t\t/*\n\t\t * SVG\n\t\t */\n\t\tvar svg = createSVGElement('svg',{\n\t\t\twidth: '100%', //options.diameter+'px',\n\t\t\theight: '100%', //options.diameter+'px',\n\t\t\tviewBox: '0 0 '+options.diameter+' '+options.diameter,\n\t\t\tclass: 'dial'\n\t\t},targetElement);\n\t\t// CIRCULAR DIAL\n\t\tvar circle = createSVGElement('circle',{\n\t\t\tcx: properties.radius,\n\t\t\tcy: properties.radius,\n\t\t\tr: properties.radius,\n\t\t\tclass: 'dial__shape'\n\t\t},svg);\n\t\t// EDITABLE INDICATOR\n\t\tvar editCircle = createSVGElement('path',{\n\t\t\td: donutPath(properties.radius,properties.radius,properties.radius-4,properties.radius-8),\n\t\t\tclass: 'dial__editableIndicator',\n\t\t},svg);\n\t\t\n\t\t/*\n\t\t * Ticks\n\t\t */\n\t\tvar ticks = createSVGElement('g',{\n\t\t\tclass: 'dial__ticks'\t\n\t\t},svg);\n\t\tvar tickPoints = [\n\t\t\t[properties.radius-1, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1, properties.ticksInnerRadius],\n\t\t\t[properties.radius-1, properties.ticksInnerRadius]\n\t\t];\n\t\tvar tickPointsLarge = [\n\t\t\t[properties.radius-1.5, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1.5, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1.5, properties.ticksInnerRadius+20],\n\t\t\t[properties.radius-1.5, properties.ticksInnerRadius+20]\n\t\t];\n\t\tvar theta = properties.tickDegrees/options.numTicks;\n\t\tvar tickArray = [];\n\t\tfor (var iTick=0; iTick<options.numTicks; iTick++) {\n\t\t\ttickArray.push(createSVGElement('path',{d:pointsToPath(tickPoints)},ticks));\n\t\t};\n\t\t\n\t\t/*\n\t\t * Labels\n\t\t */\n\t\tvar lblTarget = createSVGElement('text',{\n\t\t\tx: properties.radius,\n\t\t\ty: properties.radius,\n\t\t\tclass: 'dial__lbl dial__lbl--target'\n\t\t},svg);\n\t\tvar lblTarget_text = document.createTextNode('');\n\t\tlblTarget.appendChild(lblTarget_text);\n\t\t//\n\t\tvar lblTargetHalf = createSVGElement('text',{\n\t\t\tx: properties.radius + properties.radius/2.5,\n\t\t\ty: properties.radius - properties.radius/8,\n\t\t\tclass: 'dial__lbl dial__lbl--target--half'\n\t\t},svg);\n\t\tvar lblTargetHalf_text = document.createTextNode('5');\n\t\tlblTargetHalf.appendChild(lblTargetHalf_text);\n\t\t//\n\t\tvar lblAmbient = createSVGElement('text',{\n\t\t\tclass: 'dial__lbl dial__lbl--ambient'\n\t\t},svg);\n\t\tvar lblAmbient_text = document.createTextNode('');\n\t\tlblAmbient.appendChild(lblAmbient_text);\n\t\t//\n\t\tvar lblAway = createSVGElement('text',{\n\t\t\tx: properties.radius,\n\t\t\ty: properties.radius,\n\t\t\tclass: 'dial__lbl dial__lbl--away'\n\t\t},svg);\n\t\tvar lblAway_text = document.createTextNode('AWAY');\n\t\tlblAway.appendChild(lblAway_text);\n\t\t//\n\t\tvar lblBoost = createSVGElement('text',{\n\t\t\tx: properties.radius,\n\t\t\ty: properties.radius,\n\t\t\tclass: 'dial__lbl dial__lbl--boost'\n\t\t},svg);\n\t\tvar lblBoost_text = document.createTextNode('BOOST');\n\t\tlblBoost.appendChild(lblBoost_text);\n\t\t//\n\t\tvar icoLeaf = createSVGElement('path',{\n\t\t\tclass: 'dial__ico__leaf'\n\t\t},svg);\n\t\t\n\t\t/*\n\t\t * LEAF\n\t\t */\n\t\tvar leafScale = properties.radius/5/100;\n\t\tvar leafDef = [\"M\", 3, 84, \"c\", 24, 17, 51, 18, 73, -6, \"C\", 100, 52, 100, 22, 100, 4, \"c\", -13, 15, -37, 9, -70, 19, \"C\", 4, 32, 0, 63, 0, 76, \"c\", 6, -7, 18, -17, 33, -23, 24, -9, 34, -9, 48, -20, -9, 10, -20, 16, -43, 24, \"C\", 22, 63, 8, 78, 3, 84, \"z\"].map(function(x) {\n\t\t\treturn isNaN(x) ? x : x*leafScale;\n\t\t}).join(' ');\n\t\tvar translate = [properties.radius-(leafScale*100*0.5),properties.radius*1.5]\n\t\tvar icoLeaf = createSVGElement('path',{\n\t\t\tclass: 'dial__ico__leaf',\n\t\t\td: leafDef,\n\t\t\ttransform: 'translate('+translate[0]+','+translate[1]+')'\n\t\t},svg);\n\t\t\t\n\t\t/*\n\t\t * RENDER\n\t\t */\n\t\tfunction render() {\n\t\t\trenderAway();\n\t\t\trenderBoost();\n\t\t\trenderHvacState();\n\t\t\trenderTicks();\n\t\t\trenderTargetTemperature();\n\t\t\trenderAmbientTemperature();\n\t\t\trenderLeaf();\n\t\t}\n\t\trender();\n\n\t\t/*\n\t\t * RENDER - ticks\n\t\t */\n\t\tfunction renderTicks() {\n\t\t\tvar vMin, vMax;\n\t\t\tif ((self.away)||(self.boost)) {\n\t\t\t\tvMin = self.ambient_temperature;\n\t\t\t\tvMax = vMin;\n\t\t\t} else {\n\t\t\t\tvMin = Math.min(self.ambient_temperature, self.target_temperature);\n\t\t\t\tvMax = Math.max(self.ambient_temperature, self.target_temperature);\n\t\t\t}\n\t\t\tvar min = restrictToRange(Math.round((vMin-options.minValue)/properties.rangeValue * options.numTicks),0,options.numTicks-1);\n\t\t\tvar max = restrictToRange(Math.round((vMax-options.minValue)/properties.rangeValue * options.numTicks),0,options.numTicks-1);\n\t\t\t//\n\t\t\ttickArray.forEach(function(tick,iTick) {\n\t\t\t\tvar isLarge = iTick==min || iTick==max;\n\t\t\t\tvar isActive = iTick >= min && iTick <= max;\n\t\t\t\tattr(tick,{\n\t\t\t\t\td: pointsToPath(rotatePoints(isLarge ? tickPointsLarge: tickPoints,iTick*theta-properties.offsetDegrees,[properties.radius, properties.radius])),\n\t\t\t\t\tclass: isActive ? 'active' : ''\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t\n\t\t/*\n\t\t * RENDER - ambient temperature\n\t\t */\n\t\tfunction renderAmbientTemperature() {\n\t\t\tlblAmbient_text.nodeValue = Math.floor(self.ambient_temperature);\n\t\t\tif (self.ambient_temperature%1!=0) {\n\t\t\t\tlblAmbient_text.nodeValue += '⁵';\n\t\t\t}\n\t\t\tvar peggedValue = restrictToRange(self.ambient_temperature, options.minValue, options.maxValue);\n\t\t\tdegs = properties.tickDegrees * (peggedValue-options.minValue)/properties.rangeValue - properties.offsetDegrees;\n\t\t\tif (peggedValue > self.target_temperature) {\n\t\t\t\tdegs += 8;\n\t\t\t} else {\n\t\t\t\tdegs -= 8;\n\t\t\t}\n\t\t\tvar pos = rotatePoint(properties.lblAmbientPosition,degs,[properties.radius, properties.radius]);\n\t\t\tattr(lblAmbient,{\n\t\t\t\tx: pos[0],\n\t\t\t\ty: pos[1]\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t * RENDER - target temperature\n\t\t */\n\t\tfunction renderTargetTemperature() {\n\t\t\tlblTarget_text.nodeValue = Math.floor(self.target_temperature);\n\t\t\tsetClass(lblTargetHalf,'shown',self.target_temperature%1!=0);\n\t\t}\n\t\t\n\t\t/*\n\t\t * RENDER - leaf\n\t\t */\n\t\tfunction renderLeaf() {\n\t\t\tsetClass(svg,'has-leaf',self.has_leaf);\n\t\t}\n\t\t\n\t\t/*\n\t\t * RENDER - HVAC state\n\t\t */\n\t\tfunction renderHvacState() {\n\t\t\tArray.prototype.slice.call(svg.classList).forEach(function(c) {\n\t\t\t\tif (c.match(/^dial--state--/)) {\n\t\t\t\t\tsvg.classList.remove(c);\n\t\t\t\t};\n\t\t\t});\n\t\t\tsvg.classList.add('dial--state--'+self.hvac_state);\n\t\t}\n\t\t\n\t\t/*\n\t\t * RENDER - away\n\t\t */\n\t\tfunction renderAway() {\n\t\t\tsvg.classList[self.away ? 'add' : 'remove']('away');\n\t\t}\n\n\t\t/*\n\t\t * RENDER - boost\n\t\t */\n\t\tfunction renderBoost() {\n\t\t\tsvg.classList[self.boost ? 'add' : 'remove']('boost');\n\t\t}\n\t\t\n\t\t/*\n\t\t * Drag to control\n\t\t */\n\t\tvar _drag = {\n\t\t\tinProgress: false,\n\t\t\tstartPoint: null,\n\t\t\tstartTemperature: 0,\n\t\t\tlockAxis: undefined\n\t\t};\n\t\t\n\t\tfunction eventPosition(ev) {\n\t\t\tif (ev.targetTouches && ev.targetTouches.length) {\n\t\t\t\treturn [ev.targetTouches[0].clientX, ev.targetTouches[0].clientY];\n\t\t\t} else {\n\t\t\t\treturn [ev.x, ev.y];\n\t\t\t};\n\t\t}\n\t\t\n\t\tvar startDelay;\n\t\tfunction dragStart(ev) {\n\t\t\tstartDelay = setTimeout(function() {\n\t\t\t\tsetClass(svg, 'dial--edit', true);\n\t\t\t\t_drag.inProgress = true;\n\t\t\t\t_drag.startPoint = eventPosition(ev);\n\t\t\t\t_drag.startTemperature = self.target_temperature || options.minValue;\n\t\t\t\t_drag.lockAxis = undefined;\n\t\t\t},1000);\n\t\t};\n\t\t\n\t\tfunction dragEnd (ev) {\n\t\t\tclearTimeout(startDelay);\n\t\t\tsetClass(svg, 'dial--edit', false);\n\t\t\tif (!_drag.inProgress) return;\n\t\t\t_drag.inProgress = false;\n\t\t\tif (self.target_temperature != _drag.startTemperature) {\n\t\t\t\tif (typeof options.onSetTargetTemperature == 'function') {\n\t\t\t\t\toptions.onSetTargetTemperature(self.target_temperature);\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\t\n\t\tfunction dragMove(ev) {\n\t\t\tev.preventDefault();\n\t\t\tif (!_drag.inProgress) return;\n\t\t\tvar evPos = eventPosition(ev);\n\t\t\tvar dy = _drag.startPoint[1]-evPos[1];\n\t\t\tvar dx = evPos[0] - _drag.startPoint[0];\n\t\t\tvar dxy;\n\t\t\tif (_drag.lockAxis == 'x') {\n\t\t\t\tdxy = dx;\n\t\t\t} else if (_drag.lockAxis == 'y') {\n\t\t\t\tdxy = dy;\n\t\t\t} else if (Math.abs(dy) > properties.dragLockAxisDistance) {\n\t\t\t\t_drag.lockAxis = 'y';\n\t\t\t\tdxy = dy;\n\t\t\t} else if (Math.abs(dx) > properties.dragLockAxisDistance) {\n\t\t\t\t_drag.lockAxis = 'x';\n\t\t\t\tdxy = dx;\n\t\t\t} else {\n\t\t\t\tdxy = (Math.abs(dy) > Math.abs(dx)) ? dy : dx;\n\t\t\t};\n\t\t\tvar dValue = (dxy*getSizeRatio())/(options.diameter)*properties.rangeValue;\n\t\t\tself.target_temperature = roundHalf(_drag.startTemperature+dValue);\n\t\t}\n\t\t\n\t\tsvg.addEventListener('mousedown',dragStart);\n\t\tsvg.addEventListener('touchstart',dragStart);\n\t\t\n\t\tsvg.addEventListener('mouseup',dragEnd);\n\t\tsvg.addEventListener('mouseleave',dragEnd);\n\t\tsvg.addEventListener('touchend',dragEnd);\n\t\t\n\t\tsvg.addEventListener('mousemove',dragMove);\n\t\tsvg.addEventListener('touchmove',dragMove);\n\t\t//\n\t\t\n\t\t/*\n\t\t * Helper functions\n\t\t */\n\t\tfunction restrictTargetTemperature(t) {\n\t\t\treturn restrictToRange(roundHalf(t),options.minValue,options.maxValue);\n\t\t}\n\t\t\n\t\tfunction angle(point) {\n\t\t\tvar dx = point[0] - properties.radius;\n\t\t\tvar dy = point[1] - properties.radius;\n\t\t\tvar theta = Math.atan(dx/dy) / (Math.PI/180);\n\t\t\tif (point[0]>=properties.radius && point[1] < properties.radius) {\n\t\t\t\ttheta = 90-theta - 90;\n\t\t\t} else if (point[0]>=properties.radius && point[1] >= properties.radius) {\n\t\t\t\ttheta = 90-theta + 90;\n\t\t\t} else if (point[0]<properties.radius && point[1] >= properties.radius) {\n\t\t\t\ttheta = 90-theta + 90;\n\t\t\t} else if (point[0]<properties.radius && point[1] < properties.radius) {\n\t\t\t\ttheta = 90-theta+270;\n\t\t\t}\n\t\t\treturn theta;\n\t\t};\n\t\t\n\t\tfunction getSizeRatio() {\n\t\t\treturn options.diameter / targetElement.clientWidth;\n\t\t}\n\t\t\n\t};\n})();\n\n/* ==== */\n(function(scope) {\n \n var nest = new thermostatDial(document.getElementById('thermostat'),{\n \tonSetTargetTemperature: function(v) {\n \t\tscope.send({topic: \"target_temperature\", payload: v});\n \t}\n });\n\n\n scope.$watch('msg', function(data) {\n //console.log(data.topic+\" \"+data.payload);\n if (data.topic == \"ambient_temperature\") {\n nest.ambient_temperature = data.payload;\n } if (data.topic == \"target_temperature\") {\n nest.target_temperature = data.payload;\n } if (data.topic == \"hvac_state\") {\n nest.hvac_state = data.payload;\n } if (data.topic == \"has_leaf\") {\n nest.has_leaf = data.payload;\n } if (data.topic == \"away\") {\n nest.away = data.payload;\n } if (data.topic == \"boost\") {\n nest.boost = data.payload;\n }\n });\n})(scope);\n\n</script>","storeOutMessages":true,"fwdInMessages":false,"templateScope":"local","x":690,"y":100,"wires":[["21fd66ba.def8fa"]]},{"id":"82c7a4d2.1d8998","type":"function","z":"a91a4693.aec638","name":"ambient_temperature","func":"msg.topic = \"ambient_temperature\";\nreturn msg;","outputs":1,"noerr":0,"x":460,"y":100,"wires":[["1e740be5.c8eab4"]]},{"id":"ffa902ad.3d839","type":"function","z":"a91a4693.aec638","name":"target_temperature","func":"msg.topic = \"target_temperature\";\nreturn msg;","outputs":1,"noerr":0,"x":450,"y":140,"wires":[["1e740be5.c8eab4"]]},{"id":"c9ec6d8.c313d9","type":"function","z":"a91a4693.aec638","name":"hvac_state","func":"msg.topic = \"hvac_state\";\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":180,"wires":[["1e740be5.c8eab4"]]},{"id":"34778b8f.25d234","type":"function","z":"a91a4693.aec638","name":"has_leaf","func":"msg.topic = \"has_leaf\";\nreturn msg;","outputs":1,"noerr":0,"x":420,"y":220,"wires":[["1e740be5.c8eab4"]]},{"id":"345f31fc.a645ae","type":"function","z":"a91a4693.aec638","name":"away","func":"msg.topic = \"away\";\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":260,"wires":[["1e740be5.c8eab4"]]},{"id":"85d1d6fc.abd858","type":"inject","z":"a91a4693.aec638","name":"","topic":"has_leaf","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":true,"x":150,"y":300,"wires":[["34778b8f.25d234"]]},{"id":"c99a1af2.faa4f8","type":"inject","z":"a91a4693.aec638","name":"","topic":"has_leaf","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"x":150,"y":340,"wires":[["34778b8f.25d234"]]},{"id":"6243084.7eb40f8","type":"inject","z":"a91a4693.aec638","name":"","topic":"away","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"x":140,"y":380,"wires":[["345f31fc.a645ae"]]},{"id":"d7aa0f47.ab0d","type":"inject","z":"a91a4693.aec638","name":"","topic":"away","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"x":140,"y":420,"wires":[["345f31fc.a645ae"]]},{"id":"ffbf8da0.89546","type":"inject","z":"a91a4693.aec638","name":"","topic":"hvac_state","payload":"off","payloadType":"str","repeat":"","crontab":"","once":false,"x":150,"y":180,"wires":[["c9ec6d8.c313d9"]]},{"id":"6501277e.e6a368","type":"inject","z":"a91a4693.aec638","name":"","topic":"hvac_state","payload":"heating","payloadType":"str","repeat":"","crontab":"","once":false,"x":170,"y":220,"wires":[["c9ec6d8.c313d9"]]},{"id":"c31c6cc3.a8965","type":"inject","z":"a91a4693.aec638","name":"","topic":"hvac_state","payload":"cooling","payloadType":"str","repeat":"","crontab":"","once":false,"x":170,"y":260,"wires":[["c9ec6d8.c313d9"]]},{"id":"848f2dd3.6809d","type":"inject","z":"a91a4693.aec638","name":"","topic":"ambient_temperature","payload":"23","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":"","x":190,"y":100,"wires":[["82c7a4d2.1d8998"]]},{"id":"f02e99a2.0849b8","type":"inject","z":"a91a4693.aec638","name":"","topic":"target_temperature","payload":"20","payloadType":"num","repeat":"","crontab":"","once":true,"x":180,"y":140,"wires":[["ffa902ad.3d839"]]},{"id":"539766e6.ad21d8","type":"comment","z":"a91a4693.aec638","name":"Beca Thermostat","info":"Master read from the Beca thermostat and update\nthe values on the dashboard","x":140,"y":680,"wires":[]},{"id":"94e0cc38.18a54","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Ambient temperature","format":"{{msg.payload}} °C","layout":"row-spread","x":820,"y":780,"wires":[]},{"id":"19b53864.7c8258","type":"function","z":"a91a4693.aec638","name":"Convert data","func":"// this code collects all the individual values from the separate mqtt nodes\n// and puts them together to an object\nvar beca = context.get(\"beca\");\nif (beca===undefined) {\n beca = {};\n}\n\n// slice the topic to the part after the last slash\nvar arr = msg.topic.split(\"/\");\n\n// convert the payload to float or integer\nif (msg.payload.indexOf(\".\")!=-1) {\n msg.payload = parseFloat(msg.payload);\n} else {\n if (msg.payload.indexOf(\":\")===-1) {\n msg.payload = parseInt(msg.payload);\n }\n}\n\nif (beca[arr[arr.length-1]]!==msg.payload) {\n beca[arr[arr.length-1]]=msg.payload\n context.set(\"beca\",beca);\n msg.payload = beca;\n return msg;\n}","outputs":1,"noerr":0,"x":410,"y":720,"wires":[["bc2ea663.593388","8831c57b.d4b348","8f0bfa43.5aab68","1d39c7b4.5b1d88","ca75bb1e.6d7998"]]},{"id":"2ea3e7b5.404578","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Target temperature","format":"{{msg.payload}} °C","layout":"row-spread","x":810,"y":820,"wires":[]},{"id":"6b23359a.488d9c","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Power","format":"{{msg.payload}}","layout":"row-spread","x":770,"y":860,"wires":[]},{"id":"547af1e3.21441","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Fan speed","format":"{{msg.payload}}","layout":"row-spread","x":790,"y":1000,"wires":[]},{"id":"8c1e1451.2475f8","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Mode","format":"{{msg.payload}}","layout":"row-spread","x":770,"y":1220,"wires":[]},{"id":"ecb801a0.83315","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Time","format":"{{msg.payload}}","layout":"row-spread","x":770,"y":1400,"wires":[]},{"id":"3413de87.c89062","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Weekday","format":"{{msg.payload}}","layout":"row-spread","x":780,"y":1440,"wires":[]},{"id":"59a3f418.6e9dec","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Valve","format":"{{msg.payload}}","layout":"row-spread","x":770,"y":1500,"wires":[]},{"id":"1d39c7b4.5b1d88","type":"function","z":"a91a4693.aec638","name":"Ambient Temperature","func":"var newmsg = {};\n\nnewmsg.topic = \"ambient_temperature\";\nnewmsg.payload = msg.payload.ambient;\nreturn newmsg;","outputs":1,"noerr":0,"x":660,"y":520,"wires":[["1e740be5.c8eab4"]]},{"id":"8f0bfa43.5aab68","type":"function","z":"a91a4693.aec638","name":"Target Temperature","func":"var newmsg = {};\n\nnewmsg.topic = \"target_temperature\";\nnewmsg.payload = msg.payload.target;\n\n// This only lets the message through to the nest if it is changed. \n// This is to prevent the nest to update the temperature when it could also be edited manually\nif (context.get(\"target\")!==msg.payload.target) {\n context.set(\"target\",msg.payload.target);\n return newmsg;\n}","outputs":1,"noerr":0,"x":650,"y":560,"wires":[["1e740be5.c8eab4","e1d6ba23.e0a3b8"]]},{"id":"8831c57b.d4b348","type":"function","z":"a91a4693.aec638","name":"State","func":"var newmsg = {};\n\nnewmsg.topic = \"hvac_state\";\nif (msg.payload.power===1) {\n if (msg.payload.mode===0) { newmsg.payload = \"cooling\"; }\n if (msg.payload.mode===1) { newmsg.payload = \"heating\"; }\n if (msg.payload.mode===2) { newmsg.payload = \"heating\"; }\n} else {\n newmsg.payload = \"off\";\n}\nreturn newmsg;","outputs":1,"noerr":0,"x":650,"y":600,"wires":[["1e740be5.c8eab4"]]},{"id":"bc2ea663.593388","type":"function","z":"a91a4693.aec638","name":"Leaf","func":"var newmsg = {};\n\nnewmsg.topic = \"has_leaf\";\nif (msg.payload.mode===2) { \n newmsg.payload = true; \n} else {\n newmsg.payload = false;\n}\nreturn newmsg;","outputs":1,"noerr":0,"x":650,"y":640,"wires":[["1e740be5.c8eab4"]]},{"id":"e1d6ba23.e0a3b8","type":"ui_slider","z":"a91a4693.aec638","name":"","label":"Target Temp","group":"fc782db1.a0407","order":0,"width":0,"height":0,"passthru":false,"topic":"","min":"10","max":"40","step":"0.5","x":770,"y":240,"wires":[["f274421.62dabc","21fd66ba.def8fa"]]},{"id":"f274421.62dabc","type":"function","z":"a91a4693.aec638","name":"Target Temperature","func":"var newmsg = {};\n\nnewmsg.topic = \"target_temperature\";\nnewmsg.payload = msg.payload;\nreturn newmsg;","outputs":1,"noerr":0,"x":1010,"y":180,"wires":[["1e740be5.c8eab4"]]},{"id":"b5448b46.5c1078","type":"ui_switch","z":"a91a4693.aec638","name":"","label":"Power","group":"e4263281.60a98","order":0,"width":0,"height":0,"passthru":false,"decouple":"false","topic":"","style":"","onvalue":"1","onvalueType":"num","onicon":"","oncolor":"","offvalue":"0","offvalueType":"num","officon":"","offcolor":"","x":690,"y":940,"wires":[["e006ab08.f9fc18"]]},{"id":"b8de2220.c8b83","type":"function","z":"a91a4693.aec638","name":"Only pass changes","func":"\n// This only lets the message through if it is changed. \n// This is to prevent the UI to reset the state when it could also be edited manually\nif (context.get(\"target\")!==msg.payload) {\n context.set(\"target\",msg.payload);\nreturn msg;\n}","outputs":1,"noerr":0,"x":490,"y":940,"wires":[["b5448b46.5c1078"]]},{"id":"3277127.7bc3cee","type":"ui_dropdown","z":"a91a4693.aec638","name":"","label":"Fan speed","place":"Select option","group":"e4263281.60a98","order":0,"width":0,"height":0,"passthru":false,"options":[{"label":"Auto","value":0,"type":"num"},{"label":"High","value":"1","type":"str"},{"label":"Medium","value":"2","type":"str"},{"label":"Low","value":"3","type":"str"}],"payload":"","topic":"","x":710,"y":1160,"wires":[["4e7ad3fe.cdd66c"]]},{"id":"c49a5518.a96ad8","type":"function","z":"a91a4693.aec638","name":"Only pass changes","func":"\n// This only lets the message through if it is changed. \n// This is to prevent the UI to reset the state when it could also be edited manually\nif (context.get(\"target\")!==msg.payload) {\n context.set(\"target\",msg.payload);\nreturn msg;\n}","outputs":1,"noerr":0,"x":510,"y":1160,"wires":[["3277127.7bc3cee"]]},{"id":"70fe4930.ddad18","type":"ui_dropdown","z":"a91a4693.aec638","name":"","label":"Mode","place":"Select option","group":"e4263281.60a98","order":0,"width":0,"height":0,"passthru":false,"options":[{"label":"Cooling","value":0,"type":"num"},{"label":"Heating","value":"1","type":"str"},{"label":"Ventillation","value":"2","type":"str"}],"payload":"","topic":"","x":710,"y":1340,"wires":[["c0541619.377908"]]},{"id":"37e12418.937bfc","type":"function","z":"a91a4693.aec638","name":"Only pass changes","func":"\n// This only lets the message through if it is changed. \n// This is to prevent the UI to reset the state when it could also be edited manually\nif (context.get(\"target\")!==msg.payload) {\n context.set(\"target\",msg.payload);\nreturn msg;\n}","outputs":1,"noerr":0,"x":530,"y":1340,"wires":[["70fe4930.ddad18"]]},{"id":"12e0a82.d29fc58","type":"ui_switch","z":"a91a4693.aec638","name":"","label":"Lock","group":"e4263281.60a98","order":0,"width":0,"height":0,"passthru":false,"decouple":"false","topic":"","style":"","onvalue":"1","onvalueType":"num","onicon":"","oncolor":"","offvalue":"0","offvalueType":"num","officon":"","offcolor":"","x":690,"y":1660,"wires":[["f125b2f4.c1a98"]]},{"id":"bb00e71d.f2fed8","type":"ui_text","z":"a91a4693.aec638","group":"9caf9527.dfe288","order":0,"width":0,"height":0,"name":"","label":"Screen lock","format":"{{msg.payload}}","layout":"row-spread","x":790,"y":1580,"wires":[]},{"id":"db29277.32725d8","type":"function","z":"a91a4693.aec638","name":"Only pass changes","func":"\n// This only lets the message through if it is changed. \n// This is to prevent the UI to reset the state when it could also be edited manually\nif (context.get(\"target\")!==msg.payload) {\n context.set(\"target\",msg.payload);\nreturn msg;\n}","outputs":1,"noerr":0,"x":510,"y":1660,"wires":[["12e0a82.d29fc58"]]},{"id":"97546c0f.209eb","type":"comment","z":"a91a4693.aec638","name":"Testing the Nest features","info":"This inject nodes are left here from the example code","x":150,"y":40,"wires":[]},{"id":"64631e09.1b705","type":"comment","z":"a91a4693.aec638","name":"Setting the Target Temperature","info":"This slides sets the target temperature and updates \nthe Nest display and the modbus device as well","x":850,"y":300,"wires":[]},{"id":"4ba88e34.bc845","type":"comment","z":"a91a4693.aec638","name":"Nest update","info":"These functions generate the messages so the Nest\ncontrol shows the same temperatures as on the\nmodbus device.\n\nI needed these function nodes, because the \nNest control does not seem to accept messages\nthat have other attributes besides topic and \na simple numberic / boolean payload.","x":850,"y":580,"wires":[]},{"id":"afeb59a6.973058","type":"function","z":"a91a4693.aec638","name":"boost","func":"msg.topic = \"boost\";\nreturn msg;","outputs":1,"noerr":0,"x":410,"y":300,"wires":[["1e740be5.c8eab4"]]},{"id":"f2bbabeb.531fb8","type":"inject","z":"a91a4693.aec638","name":"","topic":"boost","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":"","x":140,"y":460,"wires":[["afeb59a6.973058"]]},{"id":"f2d1683a.4024d8","type":"inject","z":"a91a4693.aec638","name":"","topic":"boost","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":"","x":140,"y":500,"wires":[["afeb59a6.973058"]]},{"id":"e006ab08.f9fc18","type":"mqtt out","z":"a91a4693.aec638","name":"","topic":"/beca/write/power","qos":"","retain":"","broker":"cea5258a.b34038","x":870,"y":940,"wires":[]},{"id":"4e7ad3fe.cdd66c","type":"mqtt out","z":"a91a4693.aec638","name":"","topic":"/beca/write/fan","qos":"","retain":"","broker":"cea5258a.b34038","x":920,"y":1160,"wires":[]},{"id":"c0541619.377908","type":"mqtt out","z":"a91a4693.aec638","name":"","topic":"/beca/write/mode","qos":"","retain":"","broker":"cea5258a.b34038","x":890,"y":1340,"wires":[]},{"id":"f125b2f4.c1a98","type":"mqtt out","z":"a91a4693.aec638","name":"","topic":"/beca/write/lock","qos":"","retain":"","broker":"cea5258a.b34038","x":860,"y":1660,"wires":[]},{"id":"e6d35586.46dcf8","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/ambient","qos":"0","broker":"cea5258a.b34038","x":190,"y":780,"wires":[["10c5b37d.ab7ecd"]]},{"id":"26adfc61.7e9d94","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/target","qos":"0","broker":"cea5258a.b34038","x":180,"y":820,"wires":[["7c8b24eb.c435cc"]]},{"id":"f1a9deeb.9e00f","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/power","qos":"0","broker":"cea5258a.b34038","x":180,"y":860,"wires":[["b8de2220.c8b83","9069f225.04458"]]},{"id":"708d1239.841cac","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/fan","qos":"0","broker":"cea5258a.b34038","x":170,"y":1000,"wires":[["c49a5518.a96ad8","5129c9dd.b30138"]]},{"id":"969eddd0.8dd91","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/mode","qos":"0","broker":"cea5258a.b34038","x":180,"y":1220,"wires":[["37e12418.937bfc","be070abf.d70268"]]},{"id":"d320627f.44a97","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/time","qos":"0","broker":"cea5258a.b34038","x":180,"y":1400,"wires":[["ecb801a0.83315"]]},{"id":"fc8e0e7f.6939","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/weekday","qos":"0","broker":"cea5258a.b34038","x":190,"y":1440,"wires":[["3413de87.c89062"]]},{"id":"e5e289c1.779b18","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/valve","qos":"0","broker":"cea5258a.b34038","x":180,"y":1500,"wires":[["eadc8d9d.3552c"]]},{"id":"7c63f065.7d1f7","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/lock","qos":"0","broker":"cea5258a.b34038","x":180,"y":1580,"wires":[["db29277.32725d8","29467b9c.918524"]]},{"id":"9069f225.04458","type":"switch","z":"a91a4693.aec638","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":450,"y":860,"wires":[["3d56a8c8.007f78"],["ba23df28.9803a"]]},{"id":"3d56a8c8.007f78","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Off","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":860,"wires":[["6b23359a.488d9c"]]},{"id":"ba23df28.9803a","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"On","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":900,"wires":[["6b23359a.488d9c"]]},{"id":"5129c9dd.b30138","type":"switch","z":"a91a4693.aec638","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"},{"t":"eq","v":"3","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":450,"y":1000,"wires":[["f8b1a27.c73ed6"],["9a14144a.805808"],["80e27a98.17c3e8"],["c0a72338.a1f9e"]]},{"id":"f8b1a27.c73ed6","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Auto","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":1000,"wires":[["547af1e3.21441"]]},{"id":"9a14144a.805808","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"High","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":1040,"wires":[["547af1e3.21441"]]},{"id":"80e27a98.17c3e8","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Medium","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":1080,"wires":[["547af1e3.21441"]]},{"id":"c0a72338.a1f9e","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Low","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":1120,"wires":[["547af1e3.21441"]]},{"id":"be070abf.d70268","type":"switch","z":"a91a4693.aec638","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"},{"t":"eq","v":"2","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":470,"y":1220,"wires":[["257e8417.7f888c"],["834dad40.8da52"],["d0836d1d.bca0f"]]},{"id":"257e8417.7f888c","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Cooling","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":1220,"wires":[["8c1e1451.2475f8"]]},{"id":"834dad40.8da52","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Heating","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":1260,"wires":[["8c1e1451.2475f8"]]},{"id":"d0836d1d.bca0f","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Ventillation","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":1300,"wires":[["8c1e1451.2475f8"]]},{"id":"eadc8d9d.3552c","type":"switch","z":"a91a4693.aec638","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":470,"y":1500,"wires":[["35476d79.5770f2"],["36feac23.7fa864"]]},{"id":"35476d79.5770f2","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Closed","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":1500,"wires":[["59a3f418.6e9dec"]]},{"id":"36feac23.7fa864","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Open","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":1540,"wires":[["59a3f418.6e9dec"]]},{"id":"29467b9c.918524","type":"switch","z":"a91a4693.aec638","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"str"},{"t":"eq","v":"1","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":470,"y":1580,"wires":[["1964156e.21a52b"],["96cf2b12.c70988"]]},{"id":"1964156e.21a52b","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Unlocked","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":1580,"wires":[["bb00e71d.f2fed8"]]},{"id":"96cf2b12.c70988","type":"change","z":"a91a4693.aec638","name":"Text","rules":[{"t":"set","p":"payload","pt":"msg","to":"Locked","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":1620,"wires":[["bb00e71d.f2fed8"]]},{"id":"936edd03.a9c16","type":"mqtt in","z":"a91a4693.aec638","name":"","topic":"/beca/read/#","qos":"0","broker":"cea5258a.b34038","x":190,"y":720,"wires":[["19b53864.7c8258"]]},{"id":"21fd66ba.def8fa","type":"mqtt out","z":"a91a4693.aec638","name":"","topic":"/beca/write/target","qos":"","retain":"","broker":"cea5258a.b34038","x":1050,"y":240,"wires":[]},{"id":"10c5b37d.ab7ecd","type":"function","z":"a91a4693.aec638","name":"Convert to number","func":"msg.payload = parseFloat(msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":780,"wires":[["94e0cc38.18a54"]]},{"id":"7c8b24eb.c435cc","type":"function","z":"a91a4693.aec638","name":"Convert to number","func":"msg.payload = parseFloat(msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":820,"wires":[["2ea3e7b5.404578"]]},{"id":"ca75bb1e.6d7998","type":"debug","z":"a91a4693.aec638","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":630,"y":720,"wires":[]},{"id":"fc782db1.a0407","type":"ui_group","z":"","name":"Living Room","tab":"d13b4678.d56ed8","order":2,"disp":true,"width":"6","collapse":false},{"id":"9caf9527.dfe288","type":"ui_group","z":"","name":"Beca","tab":"d13b4678.d56ed8","disp":true,"width":"6","collapse":false},{"id":"e4263281.60a98","type":"ui_group","z":"","name":"Beca control","tab":"d13b4678.d56ed8","disp":true,"width":"6","collapse":false},{"id":"cea5258a.b34038","type":"mqtt-broker","z":"","broker":"192.168.1.80","port":"1883","clientid":"node-red","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"d13b4678.d56ed8","type":"ui_tab","z":"","name":"Thermostat","icon":"fa-thermometer-empty"}]