element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Arduino
  • Products
  • More
Arduino
Blog BYOB Party #12, "Creating a control page to add remote ability for your IoT of Holiday Lights"
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Arduino to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Robert Peter Oakes
  • Date Created: 19 Jan 2015 12:49 AM Date Created
  • Views 899 views
  • Likes 3 likes
  • Comments 3 comments
  • mqtt
  • html
  • iot_holidaylights
  • javascript
  • eclipse_paho
  • byob_party
Related
Recommended

BYOB Party #12, "Creating a control page to add remote ability for your IoT of Holiday Lights"

Robert Peter Oakes
Robert Peter Oakes
19 Jan 2015

Back to primary blog BYOB Party #1, "Bring you own Bulbs" - The Internet of Holiday Lights

 

At the very beginning of this project kartben (Benjamin Cabe) kindly provided a demo for using the Infinion RGB Shield and with that demo was a colour wheel web page to remotely manage the output f the RGB LEDs

 

Now while this was a great demo, my plans for world domination my challange needed more, I have utilized at least four separate MQTT topics and some sub topics also.

 

Yes you can submit publications to a topic using an MQTT client installed on your machine or use one of the several test tools out there

 

MQTT SPI or MQTT Lense to name a couple of good ones but these are generic test tools and do there job very well but its not the same as a custom control page to do the job

 

this is what I came up with

 

image

 

Forgive my lack of graphics skills, I'm a software architect, not a UI designer, I can make things work, I struggle to make them pretty

 

As you can see, most of the page is just logos and stuff, all the interesting parts on on the left side, on to ensure it is still visible to most browsers even of a small screen, secondly as I said im not a graphics UI designer

 

You will recognize the colour wheel of course, I did re-configure it to send to a different topic and also shrink it down a bit

 

This was done by adjusting two files

 

main.js - the java script file loaded up to the browser to help with local code execution

var cw = Raphael.colorwheel($(".colorwheel_small"), 300, 130).color("#00F");
cw.onchange(function(c) {
  color = c;
})

 

Change the code from .colourwheel_large to .colourwheel_small and change the size to 300, note while we are here the declaration of the call back when the wheel is changed, all it will do is set the variable color. we will use this later

 

The file main.css also needs updating as even after these changes the space the wheel ocupied was still massive even though the wheel was now a better size, i tracked this down to a style override in the CSS file

 

/* Responsive: Portrait tablets and up */
@media screen and (min-width: 300px) {
  .container {
    max-width: 300px;
  }

 

look for the above and adjust to the setting your see here, i tried this on several browsers and it worked ok in all cases, originally it was set to 780px or there about. changing just the min-width was not enough, it needed both changing

 

to point he topic to one of my choosing modify the following line

function sendColor() {
  if (connected) {
  if (color != null) {
  var message = new Paho.MQTT.Message(color.toString().replace('#', ''));
  message.destinationName = "theBreadBoard_Strip";
  client.send(message);
  color = null;
  }
  }
}

 

where is says "theBreadBoard_Strip", in the original it is "Benjamin_Strip" or similar, you can change this to suit your needs

 

OK, so now this allows the page to sent to my topic and has freed up some room for more tools

 

I have 4 topics used on my project

 

"theBreadBoard_Strip" to adjust the LED strips connected to my Infinion board, this is covered by the wheel already so nothing more to do on this end except slow it down a bit

"element14_IoT" to ping my system presence for other E14 members, I also subscribe to this to affect change in two of my units as you will see in other blogs

"NeoStar" allows me to control my STAR based on the WS2812 LED chips

"BYOB-PARTY" is used to announce the temperature of the party room and the dance floor (Do I need a jacket, I don't know, why don't I check to see how warm it will be image ) this topic also has two sub topics

"BYOB-PARTY/PartyTemp"

"BYOB-PARTY/FloorTemp

 

A single subscription topic of "BYOB-PARTY/#" will capture any changes under the BYOB-PARTY so it saves a subscription. I want to use this topic to display the temperatures on the browser, this means the browser will need to become  an MQTT subscriber, I will need to discover how to do this.

 

First things first, adding the additional publication logic for the Star and the messageing

 

looking at this code in the main.js file you will get an idea how to add functionality

client = new Paho.MQTT.Client("ws://iot.eclipse.org/ws", "id-" + new Date().getTime());

var connected = false;
function onConnect() {
  connected = true;
};


client.connect({
  onSuccess: onConnect
});

looking at the first  line you see the connection being made, the date bit at the end of the line is just to create a random client ID for the connection

next we have a variable to hold the connection status used later in the code

the function "onConnect()" is not called yet, this is the target of a call back when the connection eventually gets established

the code at line 9 above is declaring the call back, as you can see it is passing in the call the name of the call back funtion, once the connection is established, the target function is called and the variable is set.

 

function sendColor() {
  if (connected) {
  if (color != null) {
  var message = new Paho.MQTT.Message(color.toString().replace('#', ''));
  message.destinationName = "theBreadBoard_Strip";
  client.send(message);
  color = null;
  }
  }
}

This is the real working code, it sends the colour to the iot.eclipse.org site for the MQTT broker to process it, the color variable is declared at the top of the file and when this function gets called it will publish the current value but how is it called, glad you ask

 

at the very end of the file you will see this statement

setInterval(sendColor, 100);

 

it is not contained within a function so the page will execute it automatically, it sets up a re-occur timer to call the function in this case every 100mS, you may want to slow this down to say 500mS but it is a user choice

 

so thats how the basic demo page works (Without going into the operation of the wheel etc)

 

now to add my additional functionality

I need 8 buttons, one for each mode the star is programmed for, I inserted this into the HTML Body of the page (I will include as an attachment the complete code so you can see exactly where I put it)

  <table align="center">
        <tr><th style=" color:white ; align-content:center  " >Star Menues</th></tr>
        <tr><td  style="background-color:crimson" class="text-center">
            <input type="button" id="Button10" onclick="sendStar('AUTO')" value="Auto" />
            <input type="button" id="Button1" onclick="sendStar('ROTATE')" value="ROTATE"   />
            <input type="button" id="Button3" onclick="sendStar('ROTATE2')" value="ROTATE2"   />
            <input type="button" id="Button4" onclick="sendStar('EXPAND')" value="EXPAND"  />
        </td></tr>
        <tr><td  style="background-color:crimson" class="text-center">
            <input type="button" id="Button5" onclick="sendStar('EXPAND2')" value="EXPAND2"   />
            <input type="button" id="Button6" onclick="sendStar('CYCLE')" value="CYCLE"   />
            <input type="button" id="Button7" onclick="sendStar('RAINBOW')" value="RAINBOW"  />
            <input type="button" id="Button8" onclick="sendStar('WIPE')" value="WIPE" />
         </td></tr>
        </table>

 

as you can see, every button has an onclick event that calls a function called sendStar("xxx") and passes the function the command we need

the function is simply added to the main.js file

 

here it is

function sendStar(mode) {
    if (connected) {
        starMessage = mode;
        if (starMessage != null) {
            var message = new Paho.MQTT.Message(starMessage.toString());
            message.destinationName = "NeoStar";
            client.send(message);
        }
    }
}

as you can see it is pretty much identical to the color send function. easy right!, not again the use of that "connected" variable to ensure a connection was made before trying to send anything

 

between the HTML and the java script, that adds the functionality needed for the star.

the text sender is equally as simple

 

here is the HTML

     <table align="center" >
        <tr><th style=" color:antiquewhite ; align-content:center  ">Send a message to the Message Board</th></tr>
        <tr><td ><input type="text" id="myText" /><input type="button" id="Button9" onclick="sendText()" value="Send Text" /></td></tr>
    </table>

 

and here is the java function

function sendText() {
    if (connected) {
        dispMessage = document.getElementById("myText").value;
        if (dispMessage != null) {
            var message = new Paho.MQTT.Message(dispMessage.toString());
            message.destinationName = "element14_IoT";
            client.send(message);
        }
    }
}

 

again, almost identical... nice

 

ok so what about the two temperature gauges I showed you in the opening screen shot, that as it happens, ended up relatively simple too once I completed a bit of research

 

I could not easily find the info on the PAHO site but a little google goes a long way image

Server send push notifications to client browser without polling | oriolrius.cat

this still uses the PAHO libraries (Well I still stayed with them anyway), needed to perform a little on-screen (In Browser debugging to get it all working properly) but here is the result of the effort

 

at the top of the script where the connection is intially made, we need to add a call back for when messages arrive back from the broker

client = new Paho.MQTT.Client("ws://iot.eclipse.org/ws", "id-" + new Date().getTime());
client.onMessageArrived = onMessageArrived;

 

The "onConnect()" function is added to so the subscription is made automatically when the connected is made

var connected = false;
function onConnect() {
  connected = true;
  client.subscribe("BYOB-PARTY/#", { qos: 1 });
};

 

I simplified the call compared to the material I found and of course added my own topic to the subscription

now of course we need the function to receive the data

function onMessageArrived(message) {
    if (message.destinationName == 'BYOB-PARTY/PartyTemp') {
        // document.getElementById("partytemperature").innerHTML = message.payloadString;
        analog0 = message.payloadString;
    }
    else if (message.destinationName == 'BYOB-PARTY/FloorTemp') {
        //document.getElementById("floortemperature").innerHTML = message.payloadString;
        analog1 = message.payloadString;
    }
};

so this is a little different to the other functions, first of all it required some digging to discover all the additional sub elements of the message structure to allow the topic and content to be extracted, the commented out code was left there to show how to directly target a couple of div takes with IDs declared to receive the updates. I used this to get it working before adding the gauge controls

 

Pay close attention to the checking for the correct topics that the page is interested in, I discovered that there is quite a few calls made to this function in operation, not all with topic data so dont delete the check if your only looking at one topic

 

my function above checks the topic and depending on the one arrived, it will update a variable and then exit. these variables are used by the gauges automatically. I am not going to go into detail regarding the operation of the gauges as this is included in a tutorial set I have posted on the forums. for expediency, I added the scripting for the gauges to the main index.html form

this is the html to add the gauges

    <table align="center">
        <tr>
            <td ><canvas id="Canvas0"></canvas></td>
           <td ><canvas id="Canvas1"></canvas></td>
        </tr>
    </table>

 

the following script is added to the header section of the page and is the libraries so to speek

     <script>
         var Gauge = function (b) {
             function l(a, b) { for (var c in b) "object" == typeof b[c] && "[object Array]" !== Object.prototype.toString.call(b[c]) && "renderTo" != c ? ("object" != typeof a[c] && (a[c] = {}), l(a[c], b[c])) : a[c] = b[c] } function q() { z.width = b.width; z.height = b.height; A = z.cloneNode(!0); B = A.getContext("2d"); C = z.width; D = z.height; t = C / 2; u = D / 2; f = t < u ? t : u; A.i8d = !1; B.translate(t, u); B.save(); a.translate(t, u); a.save() } function v(a) {
                 var b = new Date; G = setInterval(function () {
                     var c = (new Date - b) / a.duration; 1 < c && (c = 1); var f = ("function" ==
   typeof a.delta?a.delta:M[a.delta])(c);a.step(f);1==c&&clearInterval(G)},a.delay||10)}function k(){G&&clearInterval(G);var a=I-n,h=n,c=b.animation;v({delay:c.delay,duration:c.duration,delta:c.fn,step:function(b){n=parseFloat(h)+a*b;E.draw()}})}function e(a){return a*Math.PI/180}function g(b,h,c){c=a.createLinearGradient(0,0,0,c);c.addColorStop(0,b);c.addColorStop(1,h);return c}function p(){var m=93*(f/100),h=f-m,c=91*(f/100),e=88*(f/100),d=85*(f/100);a.save();b.glow&&(a.shadowBlur=h,a.shadowColor=
   "rgba(0, 0, 0, 0.5)");a.beginPath();a.arc(0,0,m,0,2*Math.PI,!0);a.fillStyle=g("#ddd","#aaa",m);a.fill();a.restore();a.beginPath();a.arc(0,0,c,0,2*Math.PI,!0);a.fillStyle=g("#fafafa","#ccc",c);a.fill();a.beginPath();a.arc(0,0,e,0,2*Math.PI,!0);a.fillStyle=g("#eee","#f0f0f0",e);a.fill();a.beginPath();a.arc(0,0,d,0,2*Math.PI,!0);a.fillStyle=b.colors.plate;a.fill();a.save()}function w(a){var h=!1;a=0===b.majorTicksFormat.dec?Math.round(a).toString():a.toFixed(b.majorTicksFormat.dec);return 1<b.majorTicksFormat["int"]?
   (h=-1<a.indexOf("."),-1<a.indexOf("-")?"-"+(b.majorTicksFormat["int"]+b.majorTicksFormat.dec+2+(h?1:0)-a.length)+a.replace("-",""):""+(b.majorTicksFormat["int"]+b.majorTicksFormat.dec+1+(h?1:0)-a.length)+a):a}function d(){var m=81*(f/100);a.lineWidth=2;a.strokeStyle=b.colors.majorTicks;a.save();if(0===b.majorTicks.length){for(var h=(b.maxValue-b.minValue)/5,c=0;5>c;c++)b.majorTicks.push(w(b.minValue+h*c));b.majorTicks.push(w(b.maxValue))}for(c=0;c<b.majorTicks.length;++c)a.rotate(e(45+c*(270/(b.majorTicks.length-
   1)))),a.beginPath(),a.moveTo(0,m),a.lineTo(0,m-15*(f/100)),a.stroke(),a.restore(),a.save();b.strokeTicks&&(a.rotate(e(90)),a.beginPath(),a.arc(0,0,m,e(45),e(315),!1),a.stroke(),a.restore(),a.save())}function J(){var m=81*(f/100);a.lineWidth=1;a.strokeStyle=b.colors.minorTicks;a.save();for(var h=b.minorTicks*(b.majorTicks.length-1),c=0;c<h;++c)a.rotate(e(45+c*(270/h))),a.beginPath(),a.moveTo(0,m),a.lineTo(0,m-7.5*(f/100)),a.stroke(),a.restore(),a.save()}function s(){for(var m=55*(f/100),h=0;h<b.majorTicks.length;++h){var c=
   F(m,e(45+h*(270/(b.majorTicks.length-1))));a.font=20*(f/200)+"px Arial";a.fillStyle=b.colors.numbers;a.lineWidth=0;a.textAlign="center";a.fillText(b.majorTicks[h],c.x,c.y+3)}}function x(a){var h=b.valueFormat.dec,c=b.valueFormat["int"];a=parseFloat(a);var f=0>a;a=Math.abs(a);if(0<h){a=a.toFixed(h).toString().split(".");h=0;for(c-=a[0].length;h<c;++h)a[0]="0"+a[0];a=(f?"-":"")+a[0]+"."+a[1]}else{a=Math.round(a).toString();h=0;for(c-=a.length;h<c;++h)a="0"+a;a=(f?"-":"")+a}return a}function F(a,b){var c=
   Math.sin(b),f=Math.cos(b);return{x:0*f-a*c,y:0*c+a*f}}function N(){a.save();for(var m=81*(f/100),h=m-15*(f/100),c=0,g=b.highlights.length;c<g;c++){var d=b.highlights[c],r=(b.maxValue-b.minValue)/270,k=e(45+(d.from-b.minValue)/r),r=e(45+(d.to-b.minValue)/r);a.beginPath();a.rotate(e(90));a.arc(0,0,m,k,r,!1);a.restore();a.save();var l=F(h,k),p=F(m,k);a.moveTo(l.x,l.y);a.lineTo(p.x,p.y);var p=F(m,r),n=F(h,r);a.lineTo(p.x,p.y);a.lineTo(n.x,n.y);a.lineTo(l.x,l.y);a.closePath();a.fillStyle=d.color;a.fill();
       a.beginPath();a.rotate(e(90));a.arc(0,0,h,k-0.2,r+0.2,!1);a.restore();a.closePath();a.fillStyle=b.colors.plate;a.fill();a.save()}}function K(){var m=12*(f/100),h=8*(f/100),c=77*(f/100),d=20*(f/100),k=4*(f/100),r=2*(f/100),l=function(){a.shadowOffsetX=2;a.shadowOffsetY=2;a.shadowBlur=10;a.shadowColor="rgba(188, 143, 143, 0.45)"};l();a.save();n=0>n?Math.abs(b.minValue-n):0<b.minValue?n-b.minValue:Math.abs(b.minValue)+n;a.rotate(e(45+n/((b.maxValue-b.minValue)/270)));a.beginPath();a.moveTo(-r,-d);a.lineTo(-k,
       0);a.lineTo(-1,c);a.lineTo(1,c);a.lineTo(k,0);a.lineTo(r,-d);a.closePath();a.fillStyle=g(b.colors.needle.start,b.colors.needle.end,c-d);a.fill();a.beginPath();a.lineTo(-0.5,c);a.lineTo(-1,c);a.lineTo(-k,0);a.lineTo(-r,-d);a.lineTo(r/2-2,-d);a.closePath();a.fillStyle="rgba(255, 255, 255, 0.2)";a.fill();a.restore();l();a.beginPath();a.arc(0,0,m,0,2*Math.PI,!0);a.fillStyle=g("#f0f0f0","#ccc",m);a.fill();a.restore();a.beginPath();a.arc(0,0,h,0,2*Math.PI,!0);a.fillStyle=g("#e8e8e8","#f5f5f5",h);a.fill()}
             function L(){a.save();a.font=40*(f/200)+"px Led";var b=x(y),h=a.measureText("-"+x(0)).width,c=f-33*(f/100),g=0.12*f;a.save();var d=-h/2-0.025*f,e=c-g-0.04*f,h=h+0.05*f,g=g+0.07*f,k=0.025*f;a.beginPath();a.moveTo(d+k,e);a.lineTo(d+h-k,e);a.quadraticCurveTo(d+h,e,d+h,e+k);a.lineTo(d+h,e+g-k);a.quadraticCurveTo(d+h,e+g,d+h-k,e+g);a.lineTo(d+k,e+g);a.quadraticCurveTo(d,e+g,d,e+g-k);a.lineTo(d,e+k);a.quadraticCurveTo(d,e,d+k,e);a.closePath();d=a.createRadialGradient(0,c-0.12*f-0.025*f+(0.12*f+0.045*f)/
             2,f/10,0,c-0.12*f-0.025*f+(0.12*f+0.045*f)/2,f/5);d.addColorStop(0,"#888");d.addColorStop(1,"#666");a.strokeStyle=d;a.lineWidth=0.05*f;a.stroke();a.shadowBlur=0.012*f;a.shadowColor="rgba(0, 0, 0, 1)";a.fillStyle="#babab2";a.fill();a.restore();a.shadowOffsetX=0.004*f;a.shadowOffsetY=0.004*f;a.shadowBlur=0.012*f;a.shadowColor="rgba(0, 0, 0, 0.3)";a.fillStyle="#444";a.textAlign="center";a.fillText(b,-0,c);a.restore()}Gauge.Collection.push(this);this.config={renderTo:null,width:200,height:200,title:!1,
                 maxValue:100,minValue:0,majorTicks:[],minorTicks:10,strokeTicks:!0,units:!1,valueFormat:{"int":3,dec:2},majorTicksFormat:{"int":1,dec:0},glow:!0,animation:{delay:10,duration:250,fn:"cycle"},colors:{plate:"#fff",majorTicks:"#444",minorTicks:"#666",title:"#888",units:"#888",numbers:"#444",needle:{start:"rgba(240, 128, 128, 1)",end:"rgba(255, 160, 122, .9)"}},highlights:[{from:20,to:60,color:"#eee"},{from:60,to:80,color:"#ccc"},{from:80,to:100,color:"#999"}]};var y=0,E=this,n=0,I=0,H=!1;this.setValue=
                 function(a){n=b.animation?y:a;var d=(b.maxValue-b.minValue)/100;I=a>b.maxValue?b.maxValue+d:a<b.minValue?b.minValue-d:a;y=a;b.animation?k():this.draw();return this};this.setRawValue=function(a){n=y=a;this.draw();return this};this.clear=function(){y=n=I=this.config.minValue;this.draw();return this};this.getValue=function(){return y};this.onready=function(){};l(this.config,b);this.config.minValue=parseFloat(this.config.minValue);this.config.maxValue=parseFloat(this.config.maxValue);b=this.config;n=
                 y=b.minValue;if(!b.renderTo)throw Error("Canvas element was not specified when creating the Gauge object!");var z=b.renderTo.tagName?b.renderTo:document.getElementById(b.renderTo),a=z.getContext("2d"),A,C,D,t,u,f,B;q();this.updateConfig=function(a){l(this.config,a);q();this.draw();return this};var M={linear:function(a){return a},quad:function(a){return Math.pow(a,2)},quint:function(a){return Math.pow(a,5)},cycle:function(a){return 1-Math.sin(Math.acos(a))},bounce:function(a){a:{a=1-a;for(var b=0,
                 c=1;;b+=c,c/=2)if(a>=(7-4*b)/11){a=-Math.pow((11-6*b-11*a)/4,2)+Math.pow(c,2);break a}a=void 0}return 1-a},elastic:function(a){a=1-a;return 1-Math.pow(2,10*(a-1))*Math.cos(30*Math.PI/3*a)}},G=null;a.lineCap="round";this.draw=function(){if(!A.i8d){B.clearRect(-t,-u,C,D);B.save();var g={ctx:a};a=B;p();N();J();d();s();b.title&&(a.save(),a.font=24*(f/200)+"px Arial",a.fillStyle=b.colors.title,a.textAlign="center",a.fillText(b.title,0,-f/4.25),a.restore());b.units&&(a.save(),a.font=22*(f/200)+"px Arial",
                 a.fillStyle=b.colors.units,a.textAlign="center",a.fillText(b.units,0,f/3.25),a.restore());A.i8d=!0;a=g.ctx;delete g.ctx}a.clearRect(-t,-u,C,D);a.save();a.drawImage(A,-t,-u,C,D);if(Gauge.initialized)L(),K(),H||(E.onready&&E.onready(),H=!0);else var e=setInterval(function(){Gauge.initialized&&(clearInterval(e),L(),K(),H||(E.onready&&E.onready(),H=!0))},10);return this}};Gauge.initialized=!1;
         (function(){var b=document,l=b.getElementsByTagName("head")[0],q=-1!=navigator.userAgent.toLocaleLowerCase().indexOf("msie"),v="@font-face {font-family: 'Led';src: url('fonts/digital-7-mono."+(q?"eot":"ttf")+"');}",k=b.createElement("style");k.type="text/css";if(q)l.appendChild(k),l=k.styleSheet,l.cssText=v;else{try{k.appendChild(b.createTextNode(v))}catch(e){k.cssText=v}l.appendChild(k);l=k.styleSheet?k.styleSheet:k.sheet||b.styleSheets[b.styleSheets.length-1]}var g=setInterval(function(){if(b.body){clearInterval(g);
             var e=b.createElement("div");e.style.fontFamily="Led";e.style.position="absolute";e.style.height=e.style.width=0;e.style.overflow="hidden";e.innerHTML=".";b.body.appendChild(e);setTimeout(function(){Gauge.initialized=!0;e.parentNode.removeChild(e)},250)}},1)})();Gauge.Collection=[];
         Gauge.Collection.get=function(b){if("string"==typeof b)for(var l=0,q=this.length;l<q;l++){if((this[l].config.renderTo.tagName?this[l].config.renderTo:document.getElementById(this[l].config.renderTo)).getAttribute("id")==b)return this[l]}else return"number"==typeof b?this[b]:null};function domReady(b){window.addEventListener?window.addEventListener("DOMContentLoaded",b,!1):window.attachEvent("onload",b)}
         domReady(function(){function b(b){for(var e=b[0],d=1,g=b.length;d<g;d++)e+=b[d].substr(0,1).toUpperCase()+b[d].substr(1,b[d].length-1);return e}for(var l=document.getElementsByTagName("canvas"),q=0,v=l.length;q<v;q++)if("canv-gauge"==l[q].getAttribute("data-type")){var k=l[q],e={},g,p=parseInt(k.getAttribute("width"),10),w=parseInt(k.getAttribute("height"),10);e.renderTo=k;p&&(e.width=p);w&&(e.height=w);p=0;for(w=k.attributes.length;p<w;p++)if(g=k.attributes.item(p).nodeName,"data-type"!=g&&"data-"==
         g.substr(0,5)){var d=g.substr(5,g.length-5).toLowerCase().split("-");if(g=k.getAttribute(g))switch(d[0]){case "colors":d[1]&&(e.colors||(e.colors={}),"needle"==d[1]?(d=g.split(/\s+/),e.colors.needle=d[0]&&d[1]?{start:d[0],end:d[1]}:g):(d.shift(),e.colors[b(d)]=g));break;case "highlights":e.highlights||(e.highlights=[]);g=g.split(",");for(var d=0,J=g.length;d<J;d++){var s=g[d].replace(/^\s+|\s+$/g,"").split(/\s+/),x={};s[0]&&""!=s[0]&&(x.from=s[0]);s[1]&&""!=s[1]&&(x.to=s[1]);s[2]&&""!=s[2]&&(x.color=
         s[2]);e.highlights.push(x)}break;case "animation":d[1]&&(e.animation||(e.animation={}),"fn"==d[1]&&/^\s*function\s*\(/.test(g)&&(g=eval("("+g+")")),e.animation[d[1]]=g);break;default:d=b(d);if("onready"==d)continue;if("majorTicks"==d)g=g.split(/\s+/);else if("strokeTicks"==d||"glow"==d)g="true"==g?!0:!1;else if("valueFormat"==d)if(g=g.split("."),2==g.length)g={"int":parseInt(g[0],10),dec:parseInt(g[1],10)};else continue;e[d]=g}}e=new Gauge(e);k.getAttribute("data-value")&&e.setRawValue(parseFloat(k.getAttribute("data-value")));
             k.getAttribute("data-onready")&&(e.onready=function(){eval(this.config.renderTo.getAttribute("data-onready"))});e.draw()}});window.Gauge=Gauge;
       
    </script>
    <style type="text/css">
    .centerText{
   text-align: center;
}
    .divBorder {
    border: 2px solid;
    border-radius: 15px;
    width: 810px;
    text-align: center;
    box-shadow: 6px 6px 3px #888888
}
    .myRange {
    border: 2px solid;
    height: 10px;
    display: block;
    margin: 20px;
    vertical-align: middle;
    text-align: center;
    border-radius: 5px;
    background-color: #444;
    box-shadow: 6px 6px 3px #888888
}


        .auto-style3 {
            width: 123px;
            height: 28px;
        }
        .auto-style4 {
            height: 28px;
        }
        .auto-style6 {
            width: 149px;
            text-align: center;
        }


    </style>

 

below the added HTML we also need the script to configure and activate the gauges

<script>
     var gauge0 = new Gauge({
         renderTo: 'Canvas0',
         width: 200, height: 200,
         maxValue: 100,
         valueFormat: { int: 2, dec: 2 },
         glow: true,
         units: 'Deg C', title: 'Party Room',
         majorTicks: ['0', '20', '40', '60', '80', '100'],
         strokeTicks: true,
         highlights: [{from: 00,to: 20,color: 'PaleGreen'}, {from: 20,to: 60,color: 'Khaki'}, {from: 60,to: 100,color: 'LightSalmon'}],
         animation: {delay: 10, duration: 300,fn: 'bounce' }
     });
     gauge0.onready = function () { setInterval(function () { gauge0.setValue(analog0); }, 1000); };
     gauge0.draw();


     var gauge1 = new Gauge({
         renderTo: 'Canvas1',
         width: 200, height: 200,
         maxValue: 100,
         units: 'Deg C', title: 'Dance Floor',
         valueFormat: { int: 2, dec: 2 },
         glow: true,
         majorTicks: ['0', '20', '40', '60', '80', '100'],
         strokeTicks: true,
         highlights: [{ from: 00, to: 20, color: 'PaleGreen' }, { from: 20, to: 60, color: 'Khaki' }, { from: 60, to: 100, color: 'LightSalmon' }],
         animation: { delay: 10, duration: 300, fn: 'bounce' }
     });
     gauge1.onready = function () {setInterval(function () {gauge1.setValue(analog1);}, 1000);};
     gauge1.draw();
</script>

This is where you get to configure the gauges as you need, in my case, setting the size, the range of the ticks and the format of the data.

the gauge1.onready functions activate the gauges and set a timer (1000) once a second in this case and as you can see, the analog variable mentioned above is now used to pass in the current value, the nice thing here is that the receiving of MQTT data and the updating of the gauge is completely separated making the code more stable and responsive.

 

and thats all there is too it, simple right (Well straight forward anyway)

 

if you have questions, please ask, dont be afraid to try this

 

Oh and the best thing of all, this complete web solution was hosted by the Arduino YUN itself, you dont have to expose your web pages to the outside world if you dont want to, of course if you do you can, and infact Cabe's demo was hosted right from his GIT source site... sweet.

 

I will attach the complete set-up for the yun as a zip file, simply extract it and save to the root of the uSD card to go into the yu,  the rest is simple, browse to arduino.local/sd and your page will appear

 

you should end up with an Arduino folder in the root of the SD card

Attachments:
1055.arduino.zip
  • Sign in to reply
  • ipv1
    ipv1 over 10 years ago

    Bookmarked.!

    I tried setting up a webpage and then tried modifying it but my GUI turned out quite ugly. Additionally, the code got more and more complicated for me as I am not a regular at this kind if stuff. Hence in shifted to openhab which allows a rather organized GUI while abstracting a lot of presentation components. The rules are more or less js hence that's easy and I will come back to your code in an hour of need.

    Thanks

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • mcb1
    mcb1 over 10 years ago

    Sounds simple .....not.image

     

    A lot going on, well done.

    mark

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • clem57
    clem57 over 10 years ago

    Great work Robert Peter Oakes

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube