diff --git a/data/gauge.js b/data/gauge.js new file mode 100644 index 0000000..6aea775 --- /dev/null +++ b/data/gauge.js @@ -0,0 +1,27 @@ +/*! + * The MIT License (MIT) + * + * Copyright (c) 2016 Mykhailo Stadnyk + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @version 2.1.7 + */ +!function(e){"use strict";function t(e){if(Array.isArray(e)){for(var t=0,i=Array(e.length);t1&&(d=1),1!==d&&(c=r(d),isFinite(c)&&!isNaN(c)&&(d=c)),t&&t(d),s0){for(a=e.toFixed(i).toString().split("."),n=r-a[0].length;o1?(r=~i.indexOf("."),~i.indexOf("-")?"-"+[t.majorTicksInt+t.majorTicksDec+2+(r?1:0)-i.length].join("0")+i.replace("-",""):[t.majorTicksInt+t.majorTicksDec+1+(r?1:0)-i.length].join("0")+i):i}function m(e){return e*Math.PI/180}function v(e,t){return{x:-e*Math.sin(t),y:e*Math.cos(t)}}function g(e,t,i,r){var o=!(arguments.length>4&&void 0!==arguments[4])||arguments[4],n=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,a=e.createLinearGradient(o?0:n,o?n:0,o?0:r,o?r:0);return a.addColorStop(0,t),a.addColorStop(1,i),a}function b(e,t){if(arguments.length>2&&void 0!==arguments[2]&&arguments[2])return e.restore(),!0;e.save();var i=t.borderShadowWidth;return i&&(e.shadowBlur=i,e.shadowColor=t.colorBorderShadow),!0}function p(e,t){t.needleShadow&&(e.shadowOffsetX=2,e.shadowOffsetY=2,e.shadowBlur=10,e.shadowColor=t.colorNeedleShadowDown)}function w(e,t,i){return e["font"+t+"Style"]+" "+e["font"+t+"Weight"]+" "+e["font"+t+"Size"]*i+"px "+e["font"+t]}function k(e){e.shadowOffsetX=null,e.shadowOffsetY=null,e.shadowBlur=null,e.shadowColor="",e.strokeStyle=null,e.lineWidth=0,e.save()}function y(e,t,i,r){t.valueTextShadow&&(e.shadowOffsetX=i,e.shadowOffsetY=i,e.shadowBlur=r,e.shadowColor=t.colorValueTextShadow)}function x(e,t,i,r,o,n){if(t.valueBox){k(e);var a=t.valueDec?1+t.valueDec:0,l="9".repeat(Math.max.apply(null,[String(parseInt(i)).length+a].concat(t.majorTicks.map(function(e){return String(parseInt(e,10)).length+a})))),s=t.valueText||u(i,t),d=n/200,c=n/100,f=.4*c,m=1.2*c;e.font=w(t,"Value",d),y(e,t,f,m);var v=e.measureText(t.valueText?s:"-"+u(Number(l),t)).width;k(e);var g=parseFloat(t.fontValueSize)*d+f+m,b=c*parseFloat(t.valueBoxStroke),p=2*n-2*b,x=v+10*c,T=1.1*g+f+m,S=c*t.valueBoxBorderRadius,V=(parseFloat(t.valueBoxWidth)||0)/100*p;V>x&&(x=V),x>p&&(x=p);var W=r-x/2,O=o-T/2,A=o-5.75*c;if(e.beginPath(),S?h(e,W,O,x,T,S):e.rect(W,O,x,T),b){var P=e.createRadialGradient(r,A,10*c,r,A,20*c);P.addColorStop(0,t.colorValueBoxRect),P.addColorStop(1,t.colorValueBoxRectEnd),e.strokeStyle=P,e.lineWidth=b,e.stroke()}t.colorValueBoxShadow&&(e.shadowBlur=1.2*c,e.shadowColor=t.colorValueBoxShadow),t.colorValueBoxBackground&&(e.fillStyle=t.colorValueBoxBackground,e.fill()),e.closePath(),e.restore(),y(e,t,f,m),e.fillStyle=t.colorValueText,e.textAlign="center",e.textBaseline="alphabetic",e.fillText(s,W+x/2,o+T/2-g/3),e.restore()}}function T(e){var t=e.value,i=e.minValue,r=e.maxValue,o=.01*(r-i);return{normal:tr?r:t,indented:tr?r+o:t}}function S(e,t,i,r,o){i.beginPath(),i.arc(0,0,xe(e),0,2*Oe,!0),i.lineWidth=t,i.strokeStyle=o?We.linearGradient(i,r,o,e):r,i.stroke(),i.closePath()}function V(e,t){var i=pe.pixelRatio;return e.maxRadius||(e.maxRadius=e.max-t.borderShadowWidth-t.borderOuterWidth*i-t.borderMiddleWidth*i-t.borderInnerWidth*i+(t.borderOuterWidth?.5:0)+(t.borderMiddleWidth?.5:0)+(t.borderInnerWidth?.5:0)),e.maxRadius}function W(e,t){var i=pe.pixelRatio,r=t.borderShadowWidth*i,o=e.max-r-t.borderOuterWidth*i/2,n=o-t.borderOuterWidth*i/2-t.borderMiddleWidth*i/2+.5,a=n-t.borderMiddleWidth*i/2-t.borderInnerWidth*i/2+.5,l=V(e,t),s=void 0,d=!1;e.save(),t.borderOuterWidth&&(d=We.drawShadow(e,t,d),S(o,t.borderOuterWidth*i,e,t.colorBorderOuter,t.colorBorderOuterEnd)),t.borderMiddleWidth&&(d=We.drawShadow(e,t,d),S(n,t.borderMiddleWidth*i,e,t.colorBorderMiddle,t.colorBorderMiddleEnd)),t.borderInnerWidth&&(d=We.drawShadow(e,t,d),S(a,t.borderInnerWidth*i,e,t.colorBorderInner,t.colorBorderInnerEnd)),We.drawShadow(e,t,d),e.beginPath(),e.arc(0,0,xe(l),0,2*Oe,!0),t.colorPlateEnd?(s=e.createRadialGradient(0,0,l/2,0,0,l),s.addColorStop(0,t.colorPlate),s.addColorStop(1,t.colorPlateEnd)):s=t.colorPlate,e.fillStyle=s,e.fill(),e.closePath(),e.restore()}function O(e,t){var i=e.max*(parseFloat(t.highlightsWidth)||0)/100;if(i){var r=xe(P(e,t)-i/2),o=0,n=t.highlights.length,a=(t.maxValue-t.minValue)/t.ticksAngle;for(e.save();on?o:n,n>o,o>n?i:r):a,t>0?We.roundRect(e,i,r,o,n,t):e.rect(i,r,o,n),e.fill(),e.closePath()}function G(e,t,i,r,o,n,a,l,s){e.beginPath(),e.lineWidth=t,e.strokeStyle=s?We.linearGradient(e,l,s,a,!0,o):l,i>0?We.roundRect(e,r,o,n,a,i):e.rect(r,o,n,a),e.stroke(),e.closePath()}function F(e,t,i,r,o,n){var a=pe.pixelRatio;e.save();var l=t.borderRadius*a,s=o-t.borderShadowWidth-t.borderOuterWidth*a,d=s-t.borderOuterWidth*a-t.borderMiddleWidth*a,c=d-t.borderMiddleWidth*a-t.borderInnerWidth*a,h=c-t.borderInnerWidth*a,u=n-t.borderShadowWidth-t.borderOuterWidth*a,f=u-t.borderOuterWidth*a-t.borderMiddleWidth*a,m=f-t.borderMiddleWidth*a-t.borderInnerWidth*a,v=m-t.borderInnerWidth*a,g=i-(d-s)/2,b=g-(c-d)/2,p=b-(h-c)/2,w=r-(f-u)/2,k=w-(m-f)/2,y=k-(v-m)/2,x=0,T=!1;return t.borderOuterWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderOuterWidth*a,l,i+t.borderOuterWidth*a/2-x,r+t.borderOuterWidth*a/2-x,s,u,t.colorBorderOuter,t.colorBorderOuterEnd),x+=.5*a),t.borderMiddleWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderMiddleWidth*a,l-=1+2*x,g+t.borderMiddleWidth*a/2-x,w+t.borderMiddleWidth*a/2-x,d+2*x,f+2*x,t.colorBorderMiddle,t.colorBorderMiddleEnd),x+=.5*a),t.borderInnerWidth&&(T=We.drawShadow(e,t,T),G(e,t.borderInnerWidth*a,l-=1+2*x,b+t.borderInnerWidth*a/2-x,k+t.borderInnerWidth*a/2-x,c+2*x,m+2*x,t.colorBorderInner,t.colorBorderInnerEnd),x+=.5*a),We.drawShadow(e,t,T),L(e,l,p,y,h+2*x,v+2*x,t.colorPlate,t.colorPlateEnd),e.restore(),[p,y,h,v]}function X(e,t,i,r,o,n){var a=pe.pixelRatio,l=n>=o,s=l?.85*o:n,d=l?n:o;i=l?ye(i+(o-s)/2):i;var c=!!t.title,h=!!t.units,u=!!t.valueBox,f=void 0,m=void 0,v=void 0;l?(m=ye(.05*d),f=ye(.075*d),v=ye(.11*d),c&&(d-=f,r+=f),h&&(d-=m),u&&(d-=v)):(m=f=ye(.15*s),c&&(s-=f,r+=f),h&&(s-=m));var g=2*t.barStrokeWidth,b=t.barBeginCircle?ye(s*t.barBeginCircle/200-g/2):0,p=ye(s*t.barWidth/100-g),w=ye(d*t.barLength/100-g),k=ye((d-w)/2),y=ye(i+(l?s/2:k+b)),x=ye(r+(l?d-k-b+g/2:s/2)),T=!l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s,S=l||t.hasLeft&&t.hasRight?0:(t.hasRight?-1:1)*t.ticksWidth/100*s;return e.barDimensions={isVertical:l,width:s,length:d,barWidth:p,barLength:w,strokeWidth:g,barMargin:k,radius:b,pixelRatio:a,barOffset:null,titleMargin:c?f:0,unitsMargin:h?m:0,get ticksLength(){return this.barLength-this.barOffset-this.strokeWidth},X:i+T,Y:r+S,x0:y+T,y0:x+S,baseX:i,baseY:r,ticksPadding:t.ticksPadding/100},e.barDimensions}function Y(e,t,i,r,o,n,a){var l=X(e,t,r,o,n,a),s=l.isVertical,d=l.width,c=l.barWidth,h=l.barLength,u=l.strokeWidth,f=l.barMargin,m=l.radius,v=l.x0,g=l.y0,b=l.X,p=l.Y,w=h;if(e.save(),e.beginPath(),t.barBeginCircle){var k=We.radians(s?270:0),y=Math.asin(c/2/m),x=Math.cos(y),T=Math.sin(y),S=v+(s?m*T:m*x-u/2),V=s?g-m*x:g+m*T,W=xe(s?V-g:S-v);e.barDimensions.barOffset=ye(W+m);var O=s?ye(v-m*T):S,A=s?V:ye(g-m*T);"progress"===i&&(h=e.barDimensions.barOffset+(h-e.barDimensions.barOffset)*(We.normalizedValue(t).normal-t.minValue)/(t.maxValue-t.minValue));var P=ye(S+h-e.barDimensions.barOffset+u/2),M=ye(V-h+e.barDimensions.barOffset-u/2);e.arc(v,g,m,k+y,k-y),s?(e.moveTo(S,A),e.lineTo(S,M),e.lineTo(O,M),e.lineTo(O,A)):(e.moveTo(S,A),e.lineTo(P,A),e.lineTo(P,V),e.lineTo(S,V))}else{var B=ye(s?b+(d-c)/2:b+f),C=ye(s?p+h+f:p+(d-c)/2);"progress"===i&&(h*=(t.value-t.minValue)/(t.maxValue-t.minValue)),s?e.rect(B,C,c,-h):e.rect(B,C,h,c)}"progress"!==i&&t.barStrokeWidth&&(e.lineWidth=u,e.strokeStyle=t.colorBarStroke,e.stroke()),"progress"!==i&&t.colorBar?(e.fillStyle=t.colorBarEnd?We.linearGradient(e,t.colorBar,t.colorBarEnd,h,s,s?p:b):t.colorBar,e.fill()):"progress"===i&&t.colorBarProgress&&(e.fillStyle=t.colorBarProgressEnd?We.linearGradient(e,t.colorBarProgress,t.colorBarProgressEnd,w,s,s?p:b):t.colorBarProgress,e.fill()),e.closePath(),t.barBeginCircle&&(e.barDimensions.radius+=u),e.barDimensions.barWidth+=u,e.barDimensions.barLength+=u}function U(e,t,i,r,o,n){Y(e,t,"",i,r,o,n)}function q(e,t){return t.needleSide!==e||t.tickSide!==e||t.numberSide!==e}function H(e,t,i,r,o,n){t.barProgress&&Y(e,t,"progress",i,r,o,n)}function J(e,t){var i=e.barDimensions,r=i.isVertical,o=i.width,n=i.length,a=i.barWidth,l=i.barOffset,s=i.barMargin,d=i.X,c=i.Y,h=i.ticksLength,u=i.ticksPadding,f=o*(parseFloat(t.highlightsWidth)||0)/100;if(t.highlights&&f){var m="right"!==t.tickSide,v="left"!==t.tickSide,g=0,b=t.highlights.length,p=(o-a)/2,w=t.maxValue-t.minValue,k=ye(r?d+p:d+s+l),y=f,x=r?c+n-s-l:c+p,T=ye((t.ticksWidth/100+u)*o)+(f-t.ticksWidth/100*o),S=ye(a+u*o);for(e.save();gn&&(d*=-1),e.moveTo(i-h,r),e.lineTo(i+h,r),e.lineTo(i+h,r+d),e.lineTo(i,n),e.lineTo(i-h,r+d),e.lineTo(i-h,r)):(i>o&&(d*=-1),e.moveTo(i,r-h),e.lineTo(i,r+h),e.lineTo(i+d,r+h),e.lineTo(o,r),e.lineTo(i+d,r-h),e.lineTo(i,r-h)),e.fill(),e.closePath()}function se(e,t,i,r,o,n,a){var l=(parseFloat(t.fontValueSize)||0)*n/200,s=(.11*a-l)/2;e.barDimensions.isVertical&&We.drawValueBox(e,t,i,r+n/2,o+a-l-s,n)}var de=function(){function e(e,t){var i=[],r=!0,o=!1,n=void 0;try{for(var a,l=e[Symbol.iterator]();!(r=(a=l.next()).done)&&(i.push(a.value),!t||i.length!==t);r=!0);}catch(e){o=!0,n=e}finally{try{!r&&l.return&&l.return()}finally{if(o)throw n}}return i}return function(t,i){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),ce=function e(t,i,r){null===t&&(t=Function.prototype);var o=Object.getOwnPropertyDescriptor(t,i);if(void 0===o){var n=Object.getPrototypeOf(t);return null===n?void 0:e(n,i,r)}if("value"in o)return o.value;var a=o.get;if(void 0!==a)return a.call(r)},he=function e(t,i,r,o){var n=Object.getOwnPropertyDescriptor(t,i);if(void 0===n){var a=Object.getPrototypeOf(t);null!==a&&e(a,i,r,o)}else if("value"in n&&n.writable)n.value=r;else{var l=n.set;void 0!==l&&l.call(o,r)}return r},ue=function(){function e(e,t){for(var i=0;i>>0;if(0===o)return-1;var n=+t||0;if(Math.abs(n)===1/0&&(n=0),n>=o)return-1;for(i=Math.max(n>=0?n:o-Math.abs(n),0);i>>0,r=arguments[1],o=r>>0,n=o<0?Math.max(i+o,0):Math.min(o,i),a=arguments[2],l=void 0===a?i:a>>0,s=l<0?Math.max(i+l,0):Math.min(l,i);n1?r-1:0),n=1;n1?t-1:0),r=1;r=(7-4*t)/11)return-Math.pow((11-6*t-11*e)/4,2)+Math.pow(i,2)},elastic:function(e){return 1-ve.delastic(1-e)},delastic:function(e){return Math.pow(2,10*(e-1))*Math.cos(20*Math.PI*1.5/3*e)}},ge=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"linear",i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:250,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){};if(o(this,e),this.duration=i,this.rule=t,this.draw=r,this.end=n,"function"!=typeof this.draw)throw new TypeError("Invalid animation draw callback:",r);if("function"!=typeof this.end)throw new TypeError("Invalid animation end callback:",n)}return ue(e,[{key:"animate",value:function(e,t){var i=this;this.frame&&this.cancel();var r=window.performance&&window.performance.now?window.performance.now():n("animationStartTime")||Date.now();e=e||this.draw,t=t||this.end,this.draw=e,this.end=t,this.frame=me(function(o){return a(o,e,r,ve[i.rule]||i.rule,i.duration,t,i)})}},{key:"cancel",value:function(){if(this.frame){(n("cancelAnimationFrame")||function(e){})(this.frame),this.frame=null}}},{key:"destroy",value:function(){this.cancel(),this.draw=null,this.end=null}}]),e}();ge.rules=ve;var be=function(){function t(i,r,n){o(this,t),this.options=i,this.element=r.toLowerCase(),this.type=t.toDashed(n),this.Type=e[n],this.mutationsObserved=!1,this.isObservable=!!window.MutationObserver,window.GAUGES_NO_AUTO_INIT||t.domReady(this.traverse.bind(this))}return ue(t,[{key:"isValidNode",value:function(e){return!(!e.tagName||e.tagName.toLowerCase()!==this.element||e.getAttribute("data-type")!==this.type)}},{key:"traverse",value:function(){for(var e=document.getElementsByTagName(this.element),t=0,i=e.length;t1&&void 0!==arguments[1])||arguments[1],i=e.split(/-/),r=0,o=i.length,n="";r1&&void 0!==arguments[1]?arguments[1]:0;return e=parseFloat(e),!isNaN(e)&&isFinite(e)||(e=parseFloat(t)||0),e}},{key:"mod",value:function(e,t){return(e%t+t)%t}},{key:"version",get:function(){return ke}}]),n}(fe);void 0!==e&&(e.BaseGauge=Se,e.gauges=(window.document||{}).gauges=Te);var Ve=/{([_a-zA-Z]+[_a-zA-Z0-9]*)}/g,We={roundRect:h,padValue:u,formatMajorTickNumber:f,radians:m,radialPoint:v,linearGradient:g,drawNeedleShadow:p,drawValueBox:x,verifyError:s,prepareTicks:c,drawShadow:b,font:w,normalizedValue:T,formatContext:d},Oe=Math.PI,Ae=Oe/2,Pe=Object.assign({},we,{ticksAngle:270,startAngle:45,colorNeedleCircleOuter:"#f0f0f0",colorNeedleCircleOuterEnd:"#ccc",colorNeedleCircleInner:"#e8e8e8",colorNeedleCircleInnerEnd:"#f5f5f5",needleCircleSize:10,needleCircleInner:!0,needleCircleOuter:!0,needleStart:20,animationTarget:"needle",useMinPath:!1,barWidth:0,barStartPosition:"left"}),Me=function(e){function t(e){return o(this,t),e=Object.assign({},Pe,e||{}),i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,t.configure(e)))}return r(t,e),ue(t,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],n=i[2],a=i[3],l=this.options;if("needle"===l.animationTarget){if(!e.elementClone.initialized){var s=e.contextClone;s.clearRect(r,o,n,a),s.save(),this.emit("beforePlate"),W(s,l),this.emit("beforeHighlights"),O(s,l),this.emit("beforeMinorTicks"),A(s,l),this.emit("beforeMajorTicks"),M(s,l),this.emit("beforeNumbers"),j(s,l),this.emit("beforeTitle"),N(s,l),this.emit("beforeUnits"),E(s,l),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,n,a),e.context.save(),e.context.drawImage(e.elementClone,r,o,n,a),e.context.save(),this.emit("beforeProgressBar"),D(e.context,l),this.emit("beforeValueBox"),R(e.context,l,z(this)),this.emit("beforeNeedle"),_(e.context,l)}else{var d=-We.radians((l.value-l.minValue)/(l.maxValue-l.minValue)*l.ticksAngle);if(e.context.clearRect(r,o,n,a),e.context.save(),this.emit("beforePlate"),W(e.context,l),e.context.rotate(d),this.emit("beforeHighlights"),O(e.context,l),this.emit("beforeMinorTicks"),A(e.context,l),this.emit("beforeMajorTicks"),M(e.context,l),this.emit("beforeNumbers"),j(e.context,l),this.emit("beforeProgressBar"),D(e.context,l),e.context.rotate(-d),e.context.save(),!e.elementClone.initialized){var c=e.contextClone;c.clearRect(r,o,n,a),c.save(),this.emit("beforeTitle"),N(c,l),this.emit("beforeUnits"),E(c,l),this.emit("beforeNeedle"),_(c,l),e.elementClone.initialized=!0}e.context.drawImage(e.elementClone,r,o,n,a)}this.emit("beforeValueBox"),R(e.context,l,z(this)),ce(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"draw",this).call(this)}catch(e){We.verifyError(e)}return this}},{key:"value",set:function(e){e=Se.ensureValue(e,this.options.minValue),this.options.animation&&360===this.options.ticksAngle&&this.options.useMinPath&&(this._value=e,e=this.options.value+((e-this.options.value)%360+540)%360-180),he(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",e,this)},get:function(){return ce(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"value",this)}}],[{key:"configure",value:function(e){return e.barWidth>50&&(e.barWidth=50),isNaN(e.startAngle)&&(e.startAngle=45),isNaN(e.ticksAngle)&&(e.ticksAngle=270),e.ticksAngle>360&&(e.ticksAngle=360),e.ticksAngle<0&&(e.ticksAngle=0),e.startAngle<0&&(e.startAngle=0),e.startAngle>360&&(e.startAngle=360),e}}]),t}(Se);void 0!==e&&(e.RadialGauge=Me),Se.initialize("RadialGauge",Pe);var Be=Object.assign({},we,{borderRadius:0,barBeginCircle:30,colorBarEnd:"",colorBarProgressEnd:"",needleWidth:6,tickSide:"both",needleSide:"both",numberSide:"both",ticksWidth:10,ticksWidthMinor:5,ticksPadding:5,barLength:85,fontTitleSize:26,highlightsWidth:10}),Ce=function(e){function n(e){return o(this,n),e=Object.assign({},Be,e||{}),i(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,n.configure(e)))}return r(n,e),ue(n,[{key:"draw",value:function(){try{var e=this.canvas,i=[-e.drawX,-e.drawY,e.drawWidth,e.drawHeight],r=i[0],o=i[1],a=i[2],l=i[3],s=this.options;if(!e.elementClone.initialized){var d=e.contextClone;d.clearRect(r,o,a,l),d.save(),this.emit("beforePlate"),this.drawBox=F(d,s,r,o,a,l),this.emit("beforeBar"),U.apply(void 0,[d,s].concat(t(this.drawBox))),e.context.barDimensions=d.barDimensions,this.emit("beforeHighlights"),J(d,s),this.emit("beforeMinorTicks"),ee(d,s),this.emit("beforeMajorTicks"),K(d,s),this.emit("beforeNumbers"),te(d,s),this.emit("beforeTitle"),ie(d,s),this.emit("beforeUnits"),re(d,s),e.elementClone.initialized=!0}this.canvas.commit(),e.context.clearRect(r,o,a,l),e.context.save(),e.context.drawImage(e.elementClone,r,o,a,l),e.context.save(),this.emit("beforeProgressBar"),H.apply(void 0,[e.context,s].concat(t(this.drawBox))),this.emit("beforeNeedle"),oe(e.context,s),this.emit("beforeValueBox"),se.apply(void 0,[e.context,s,s.animatedValue?this.options.value:this.value].concat(t(this.drawBox))),ce(n.prototype.__proto__||Object.getPrototypeOf(n.prototype),"draw",this).call(this)}catch(e){We.verifyError(e)}return this}}],[{key:"configure",value:function(e){return e.barStrokeWidth>=e.barWidth&&(e.barStrokeWidth=ye(e.barWidth/2)),e.hasLeft=q("right",e),e.hasRight=q("left",e),e.value>e.maxValue&&(e.value=e.maxValue),e.value { }); } + + fetchData(); // fetch immediately on page load setInterval(fetchData, 5000); // fetch every 5 seconds }); function roundToTwo(num) { return Math.round(num*100)/100; -} \ No newline at end of file +} + +window.addEventListener('load', function () { + var gauge = new RadialGauge({ + renderTo: 'main_gauge', + width: 300, + height: 300, + units: "l", + minValue: 0, + maxValue: 220, + majorTicks: [ + "0", + "20", + "40", + "60", + "80", + "100", + "120", + "140", + "160", + "180", + "200", + "220" + ], + minorTicks: 2, + strokeTicks: true, + highlights: [ + { + "from": 160, + "to": 220, + "color": "rgba(200, 50, 50, .75)" + } + ], + colorPlate: "#fff", + borderShadowWidth: 0, + borders: false, + needleType: "arrow", + needleWidth: 2, + needleCircleSize: 7, + needleCircleOuter: true, + needleCircleInner: false, + animationDuration: 1500, + animationRule: "linear" + }).draw(); + }) + + +// document.body.appendChild(gauge.options.renderTo); \ No newline at end of file diff --git a/data/settings.html b/data/settings.html index 89d0377..96cdb6b 100644 --- a/data/settings.html +++ b/data/settings.html @@ -25,22 +25,22 @@ Settings

- +

- +

- +

- +

- +

@@ -55,15 +55,15 @@

- +

- +

- +

diff --git a/data/status.html b/data/status.html index 35b3be2..96d1d2d 100644 --- a/data/status.html +++ b/data/status.html @@ -2,7 +2,10 @@ + + + @@ -70,13 +73,7 @@
-
-
-
-
-
25%
-
2500 / 10000
-
+
diff --git a/dev/Waterlevel/Update Sensor Settings.bru b/dev/Waterlevel/Update Sensor Settings.bru new file mode 100644 index 0000000..d490b0d --- /dev/null +++ b/dev/Waterlevel/Update Sensor Settings.bru @@ -0,0 +1,18 @@ +meta { + name: Update Sensor Settings + type: http + seq: 2 +} + +post { + url: http://192.168.5.181/update_sensor_settings + body: multipartForm + auth: none +} + +body:multipart-form { + sensor_range: 200 + water_level_max: 190 + water_level_min: 10 + water_volume: 1000 +} diff --git a/dev/Waterlevel/bruno.json b/dev/Waterlevel/bruno.json new file mode 100644 index 0000000..0b760d4 --- /dev/null +++ b/dev/Waterlevel/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "Waterlevel", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/src/global_data/defines.h b/src/global_data/defines.h new file mode 100644 index 0000000..42c3a95 --- /dev/null +++ b/src/global_data/defines.h @@ -0,0 +1,9 @@ +// Define keys to prevent typos +#define ssid_key "ssid" +#define wifi_password_key "wifi_password" +#define level_sensor_range_key "sensor_range" +#define water_level_min_key "water_level_min" +#define water_level_max_key "water_level_max" +#define water_volume_key "water_volume" + +#define RESISTOR_VALUE 4 \ No newline at end of file diff --git a/src/global_data/global_data.cpp b/src/global_data/global_data.cpp new file mode 100644 index 0000000..aee4177 --- /dev/null +++ b/src/global_data/global_data.cpp @@ -0,0 +1,10 @@ +#include "global_data.h" + +NetworkData wifi_data; +NetworkData ethernet_data; +DeviceTelemetry telemetry; + +SensorData shunt_data; +WaterData water_data; + +ActiveErrors active_errors = { false, false, false, false, false, false }; \ No newline at end of file diff --git a/src/global_data/global_data.h b/src/global_data/global_data.h new file mode 100644 index 0000000..e9cb5ef --- /dev/null +++ b/src/global_data/global_data.h @@ -0,0 +1,38 @@ +#include + +struct SensorData { + float bus_voltage; + float shunt_voltage; + float shunt_current; +}; + +struct WaterData{ + // Water level in cm + float level; + // Water volume in liters + float liters; + // Percentage + float percentage; +}; + + +struct NetworkData { + String ip_address; + bool link; + float rssi; + String network_name; +}; + +struct DeviceTelemetry { + float heap_used_percent; + int uptime_seconds; +}; + +struct ActiveErrors { + bool voltage_low; + bool voltage_high; + bool current_low; + bool current_high; + bool level_low; + bool level_high; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 8be745d..4922b12 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,11 +12,16 @@ #include #include "INA226.h" -#include "Wire.h" #include "INA233.h" +#include "global_data/defines.h" + +#include "networking/networking.h" + #include +#include "global_data/global_data.h" +#include "sensor/sensor.h" #define LED_1 4 #define LED_2 2 @@ -25,73 +30,17 @@ #define LED_5 12 #define LED_RED 14 -// Define keys to prevent typos -#define ssid_key "ssid" -#define wifi_password_key "wifi_password" -#define level_sensor_range_key "range" -#define water_level_min_key "level_min" -#define water_level_max_key "level_max" -#define liters_key "liters" - -#define RESISTOR_VALUE 4 - extern "C" int rom_phy_get_vdd33(); -// Calibration variables -float zero_value = 0.03; // Measured shunt voltage with nothing connected, used to fix measuring offset -bool voltage_high = false; -bool voltage_low = false; -bool current_high = false; -bool current_low = false; +extern NetworkData wifi_data; +extern NetworkData ethernet_data; +extern DeviceTelemetry telemetry; -uint8_t failed_connection_attempts = 0; +extern SensorData shunt_data; +extern WaterData water_data; -struct SensorData { - float bus_voltage; - float shunt_voltage; - float shunt_current; -}; - -struct WaterData{ - // Water level in cm - float level; - // Water volume in liters - float liters; - // Percentage - float percentage; -}; - - -struct NetworkData { - String ip_address; - bool link; - float rssi; - String network_name; -}; - -struct DeviceTelemetry { - float heap_used_percent; - int uptime_seconds; -}; - -NetworkData wifi_data; -NetworkData ethernet_data; -DeviceTelemetry telemetry; - -SensorData shunt_data; -WaterData water_data; - -int64_t mac_address = ESP.getEfuseMac(); - - -//#define USE_INA226 - -#ifdef USE_INA226 -INA226 ina_sensor(0x40); -#else -INA233 ina_sensor(0x40); -#endif +extern ActiveErrors active_errors; Preferences prefs; @@ -159,7 +108,7 @@ void display_error_code(byte err_code) bool is_error() { - return voltage_high || voltage_low || current_high || current_low; + return active_errors.voltage_high || active_errors.voltage_low || active_errors.current_high || active_errors.current_low; } void printSuffix(Print* _logOutput, int logLevel) @@ -186,16 +135,16 @@ void display_task(void* parameter) Log.verbose("Error detected"); // We have an error, display error code for 3 seconds and then water level for 3 seconds - if (voltage_low) { + if (active_errors.voltage_low) { display_error_code(1); delay(3000); - } else if (voltage_high) { + } else if (active_errors.voltage_high) { display_error_code(2); delay(3000); - } else if (current_low) { + } else if (active_errors.current_low) { display_error_code(3); delay(3000); - } else if (current_high) { + } else if (active_errors.current_high) { display_error_code(4); delay(3000); } else { @@ -206,63 +155,6 @@ void display_task(void* parameter) } } -void wifi_task(void* parameter) -{ - Log.verbose("Starting WiFi Task"); - while (true) { - if (prefs.getString(ssid_key, "") == "" || failed_connection_attempts > 5) { - wifi_data.link = false; - if (failed_connection_attempts > 5) { - Log.verbose("Failed to connecto to currently saved SSID, starting SoftAP"); - } else { - Log.verbose("No SSID saved, starting SoftAP"); - } - - String ap_ssid = "Watermeter-" + String(mac_address); - WiFi.softAP(ap_ssid, ""); - - Log.verbose("[WIFI_TASK] Waiting for SSID now..."); - - String old_ssid = prefs.getString(ssid_key, "xxx"); - while (prefs.getString(ssid_key, "") == "" || prefs.getString(ssid_key, "") == old_ssid) { - delay(5000); - } - - failed_connection_attempts = 0; - } else { - if (WiFi.isConnected() && WiFi.SSID() == prefs.getString(ssid_key, "")) { - failed_connection_attempts = 0; - wifi_data.rssi = WiFi.RSSI(); - wifi_data.link = true; - wifi_data.network_name = WiFi.SSID(); - wifi_data.ip_address = WiFi.localIP().toString(); - - Log.verbose("RSSI: %F, IP Address, %p, SSID: %s", float(WiFi.RSSI()), WiFi.localIP(), prefs.getString(ssid_key, "NOSSID")); - delay(5000); - } else { - Log.verbose("Connecting to %s using password %s", prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, "")); - WiFi.mode(WIFI_STA); - WiFi.begin(prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, "")); - failed_connection_attempts++; - delay(5000); - } - } - } -} - -void ethernet_task(void* parameter) -{ - Log.verbose("Connecting Ethernet"); - ETH.begin(0, 17, 23, 18); - ETH.setHostname("watermeter"); - while (true) { - ethernet_data.link = ETH.linkUp(); - ethernet_data.rssi = ETH.linkSpeed(); - ethernet_data.ip_address = ETH.localIP().toString(); - delay(60 * 1000); - } -} - void collect_internal_telemetry_task(void* parameter) { while (true) { @@ -275,70 +167,24 @@ void collect_internal_telemetry_task(void* parameter) } } -void read_sensor_task(void* parameter) + + +String processor(const String& var) { - while (true) { - // Get Values from sensor - - float bus_voltage = ina_sensor.getBusVoltage(); - float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value; - - float shunt_current = shunt_voltage / RESISTOR_VALUE; - - // Get values from storage - float sensor_range = prefs.getFloat(level_sensor_range_key, 200); - float max_water_level = prefs.getFloat(water_level_max_key, sensor_range); - float min_water_level = prefs.getFloat(water_level_min_key, 0); - float max_liters = prefs.getFloat(liters_key, 10000.); - - float mA_per_cm = (20. - 4.) / (sensor_range); - - // Get mA over 0cm/4mA for max/min water level - float min_water_level_mA_over_zero = (min_water_level * mA_per_cm); - float max_water_level_mA_over_zero = (max_water_level * mA_per_cm); - - // Levels which represent raw sensor value, with 4mA added - float min_water_level_mA = 4 + min_water_level_mA_over_zero; - float max_water_level_mA = 4 + max_water_level_mA_over_zero; - - Log.verbose("max_water_level_mA: %F", max_water_level_mA); - Log.verbose("min_water_level_mA_over_zero: %F", min_water_level_mA_over_zero); - - // Current over the 0 level of the water - float shunt_current_over_zero = shunt_current - min_water_level_mA; - - // cm over zero water level - float cm_over_zero = shunt_current_over_zero / mA_per_cm; - - // Raw unrounded percentage in decimal - float percentage_raw = (shunt_current_over_zero / (max_water_level_mA_over_zero - min_water_level_mA_over_zero)); - float percentage_rounded = round(percentage_raw*100); - - // Tank volume in liters - float liters_raw = max_liters * percentage_raw; - int liters = round(liters_raw); - - current_low = shunt_current < 3.8; - current_high = shunt_current > 20.2; - voltage_low = bus_voltage < 23; - voltage_high = bus_voltage > 25; - Log.verbose("Shunt current: %F", shunt_current); - Log.verbose("Shunt voltage: %F", shunt_voltage); - Log.verbose("Bus voltage: %F", bus_voltage); - Log.verbose("cm_over_zero: %F", cm_over_zero); - - shunt_data.bus_voltage = bus_voltage; - shunt_data.shunt_voltage = shunt_voltage; - shunt_data.shunt_current = shunt_current; - - water_data.level = cm_over_zero; - water_data.liters = liters; - water_data.percentage = percentage_rounded; - - delay(20000); - } + if (var == level_sensor_range_key) { + return String(prefs.getFloat(level_sensor_range_key, -1)); + } else if (var == water_level_min_key) { + return String(prefs.getFloat(water_level_min_key, -1)); + } else if (var == water_level_max_key) { + return String(prefs.getFloat(water_level_max_key, -1)); + } else if (var == water_volume_key) { + return String(prefs.getFloat(water_volume_key, -1)); + } + + return String("Test"); } + void setup() { prefs.begin("waterlevel", false); @@ -358,6 +204,7 @@ void setup() display_error_code(31); delay(500); display_error_code(17); + init_sensor(); Log.verbose("Beginning SPIFFS"); SPIFFS.begin(true); @@ -365,26 +212,15 @@ void setup() display_error_code(19); Log.verbose("Begin INA"); - ina_sensor.begin(33, 32); - display_error_code(20); - #ifdef USE_INA226 - ina_sensor.setMaxCurrentShunt(0.02, 4, false); - ina_sensor.setBusVoltageConversionTime(7); - ina_sensor.setShuntVoltageConversionTime(7); - ina_sensor.setAverage(4); - #else - ina_sensor.setShuntVoltageConversionTime(conversion_time_8244uS); - ina_sensor.setBusVoltageConversionTime(conversion_time_8244uS); - ina_sensor.setAveragingMode(averages_128); - #endif + display_error_code(22); /////////////////////////////// ROUTES /////////////////////////////// Log.verbose("Route Setup"); - server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/status.html", "text/html", false); }); + server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/status.html", "text/html", false, processor); }); - server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/settings.html", "text/html", false); }); + server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/settings.html", "text/html", false, processor); }); server.on("/export", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/data_export.html", "text/html", false); }); @@ -393,13 +229,15 @@ void setup() server.on("/update_wifi_credentials", HTTP_POST, [](AsyncWebServerRequest* request) { int params = request->params(); + // For settings SSID if (request->hasParam(ssid_key, true) && request->hasParam(wifi_password_key, true)) { Log.verbose("Updating SSID config"); AsyncWebParameter* ssid_param = request->getParam(ssid_key, true); AsyncWebParameter* password_param = request->getParam(wifi_password_key, true); prefs.putString(ssid_key, ssid_param->value().c_str()); prefs.putString(wifi_password_key, password_param->value().c_str()); - } else { + + }else { for (int i = 0; i < params; i++) { AsyncWebParameter* p = request->getParam(i); if (p->isFile()) { // p->isPost() is also true @@ -418,17 +256,37 @@ void setup() server.on("/update_sensor_settings", HTTP_POST, [](AsyncWebServerRequest* request) { int params = request->params(); - if (request->hasParam(level_sensor_range_key, true) && request->hasParam(water_level_min_key, true) && request->hasParam(water_level_max_key, true) && request->hasParam(liters_key, true)) { + if (request->hasParam(level_sensor_range_key, true) && request->hasParam(water_level_min_key, true) && request->hasParam(water_level_max_key, true) && request->hasParam(water_volume_key, true)) { Log.verbose("Updating Sensor config"); AsyncWebParameter* range_param = request->getParam(level_sensor_range_key, true); AsyncWebParameter* level_min_param = request->getParam(water_level_min_key, true); AsyncWebParameter* level_max_param = request->getParam(water_level_max_key, true); - AsyncWebParameter* liters_param = request->getParam(liters_key, true); + AsyncWebParameter* liters_param = request->getParam(water_volume_key, true); - prefs.putFloat(level_sensor_range_key, range_param->value().toFloat()); - prefs.putFloat(water_level_min_key, level_min_param->value().toFloat()); - prefs.putFloat(water_level_max_key, level_max_param->value().toFloat()); - prefs.putFloat(liters_key, liters_param->value().toFloat()); + String range_str = range_param->value(); + String level_min_str = level_min_param->value(); + String level_max_str = level_max_param->value(); + String liters_str = liters_param->value(); + + float range_float = range_str.toFloat(); + float level_min_float = level_min_str.toFloat(); + float level_max_float = level_max_str.toFloat(); + float liters_float = liters_str.toFloat(); + + const char* paramCStr = range_str.c_str(); + char* endPtr; + + // Convert the C string to a float using strtod + float value = strtod(paramCStr, &endPtr); + + Log.verbose("range_float:%D:", range_float); + + prefs.putFloat(level_sensor_range_key, range_float); + prefs.putFloat(water_level_min_key, level_min_float); + prefs.putFloat(water_level_max_key, level_max_float); + prefs.putFloat(water_volume_key, liters_float); + + Log.verbose("range_float_after:%D:", prefs.getFloat(level_sensor_range_key, -1.0)); } else { Log.verbose("!!!! FAIL lo"); for (int i = 0; i < params; i++) { @@ -492,6 +350,8 @@ void setup() }); server.on("/chota.css", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/chota.css", "text/css", false); }); + server.on("/gauge.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/gauge.js", "application/javascript", false); }); + display_error_code(23); diff --git a/src/networking/networking.cpp b/src/networking/networking.cpp new file mode 100644 index 0000000..d90c005 --- /dev/null +++ b/src/networking/networking.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include "../global_data/defines.h" +#include "../global_data/global_data.h" +#include + +int64_t mac_address = ESP.getEfuseMac(); +uint8_t failed_connection_attempts = 0; + +extern NetworkData wifi_data; +extern NetworkData ethernet_data; +extern Preferences prefs; + +void wifi_task(void* parameter) +{ + Log.verbose("Starting WiFi Task"); + while (true) { + if (prefs.getString(ssid_key, "") == "" || failed_connection_attempts > 5) { + wifi_data.link = false; + if (failed_connection_attempts > 5) { + Log.verbose("Failed to connecto to currently saved SSID, starting SoftAP"); + } else { + Log.verbose("No SSID saved, starting SoftAP"); + } + + String ap_ssid = "Watermeter-" + String(mac_address); + WiFi.softAP(ap_ssid, ""); + + Log.verbose("[WIFI_TASK] Waiting for SSID now..."); + + String old_ssid = prefs.getString(ssid_key, "xxx"); + while (prefs.getString(ssid_key, "") == "" || prefs.getString(ssid_key, "") == old_ssid) { + delay(5000); + } + + failed_connection_attempts = 0; + } else { + if (WiFi.isConnected() && WiFi.SSID() == prefs.getString(ssid_key, "")) { + failed_connection_attempts = 0; + wifi_data.rssi = WiFi.RSSI(); + wifi_data.link = true; + wifi_data.network_name = WiFi.SSID(); + wifi_data.ip_address = WiFi.localIP().toString(); + + Log.verbose("RSSI: %F, IP Address, %p, SSID: %s", float(WiFi.RSSI()), WiFi.localIP(), prefs.getString(ssid_key, "NOSSID")); + delay(5000); + } else { + Log.verbose("Connecting to %s using password %s", prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, "")); + WiFi.mode(WIFI_STA); + WiFi.begin(prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, "")); + failed_connection_attempts++; + delay(5000); + } + } + } +} + +void ethernet_task(void* parameter) +{ + Log.verbose("Connecting Ethernet"); + ETH.begin(0, 17, 23, 18); + ETH.setHostname("watermeter"); + while (true) { + ethernet_data.link = ETH.linkUp(); + ethernet_data.rssi = ETH.linkSpeed(); + ethernet_data.ip_address = ETH.localIP().toString(); + delay(60 * 1000); + } +} diff --git a/src/networking/networking.h b/src/networking/networking.h new file mode 100644 index 0000000..1bcd3dc --- /dev/null +++ b/src/networking/networking.h @@ -0,0 +1,2 @@ +void wifi_task(void*); +void ethernet_task(void*); \ No newline at end of file diff --git a/src/sensor/sensor.cpp b/src/sensor/sensor.cpp new file mode 100644 index 0000000..4da4a5d --- /dev/null +++ b/src/sensor/sensor.cpp @@ -0,0 +1,99 @@ +#include "../global_data/defines.h" +#include +#include +#include +#include +#include "Wire.h" + + +#ifdef USE_INA226s +INA226 ina_sensor(0x40); +#else +INA233 ina_sensor(0x40); +#endif + +extern Preferences prefs; +extern WaterData water_data; +extern ActiveErrors active_errors; +extern SensorData shunt_data; + +// Calibration variables +float zero_value = 0.03; // Measured shunt voltage with nothing connected, used to fix measuring offset + +void init_sensor(){ + ina_sensor.begin(33, 32); + #ifdef USE_INA226 + ina_sensor.setMaxCurrentShunt(0.02, 4, false); + ina_sensor.setBusVoltageConversionTime(7); + ina_sensor.setShuntVoltageConversionTime(7); + ina_sensor.setAverage(4); + #else + ina_sensor.setShuntVoltageConversionTime(conversion_time_8244uS); + ina_sensor.setBusVoltageConversionTime(conversion_time_8244uS); + ina_sensor.setAveragingMode(averages_128); + #endif +} + +void read_sensor_task(void* parameter) +{ + while (true) { + // Get Values from sensor + + float bus_voltage = ina_sensor.getBusVoltage(); + float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value; + + float shunt_current = shunt_voltage / RESISTOR_VALUE; + + // Get values from storage + float sensor_range = prefs.getFloat(level_sensor_range_key, 200); + float max_water_level = prefs.getFloat(water_level_max_key, sensor_range); + float min_water_level = prefs.getFloat(water_level_min_key, 0); + float max_liters = prefs.getFloat(water_volume_key, 10000.); + + float mA_per_cm = (20. - 4.) / (sensor_range); + + // Get mA over 0cm/4mA for max/min water level + float min_water_level_mA_over_zero = (min_water_level * mA_per_cm); + float max_water_level_mA_over_zero = (max_water_level * mA_per_cm); + + // Levels which represent raw sensor value, with 4mA added + float min_water_level_mA = 4 + min_water_level_mA_over_zero; + float max_water_level_mA = 4 + max_water_level_mA_over_zero; + + Log.verbose("max_water_level_mA: %F", max_water_level_mA); + Log.verbose("min_water_level_mA_over_zero: %F", min_water_level_mA_over_zero); + + // Current over the 0 level of the water + float shunt_current_over_zero = shunt_current - min_water_level_mA; + + // cm over zero water level + float cm_over_zero = shunt_current_over_zero / mA_per_cm; + + // Raw unrounded percentage in decimal + float percentage_raw = (shunt_current_over_zero / (max_water_level_mA_over_zero - min_water_level_mA_over_zero)); + float percentage_rounded = round(percentage_raw*100); + + // Tank volume in liters + float liters_raw = max_liters * percentage_raw; + int liters = round(liters_raw); + + active_errors.current_low = shunt_current < 3.8; + active_errors.current_high = shunt_current > 20.2; + active_errors.voltage_low = bus_voltage < 23; + active_errors.voltage_high = bus_voltage > 25; + Log.verbose("Shunt current: %F", shunt_current); + Log.verbose("Shunt voltage: %F", shunt_voltage); + Log.verbose("Bus voltage: %F", bus_voltage); + Log.verbose("cm_over_zero: %F", cm_over_zero); + + shunt_data.bus_voltage = bus_voltage; + shunt_data.shunt_voltage = shunt_voltage; + shunt_data.shunt_current = shunt_current; + + water_data.level = cm_over_zero; + water_data.liters = liters; + water_data.percentage = percentage_rounded; + + delay(20000); + } +} \ No newline at end of file diff --git a/src/sensor/sensor.h b/src/sensor/sensor.h new file mode 100644 index 0000000..0b5cf03 --- /dev/null +++ b/src/sensor/sensor.h @@ -0,0 +1,2 @@ +void read_sensor_task(void*); +void init_sensor(); \ No newline at end of file