Slider to control PWM & Broadcast

Started by jorgmuskens, January 14, 2016, 06:46:54 PM

jorgmuskens

Hi Felix,
I was wondering if there's a metric that i can use which can be attached to a slider controller. The value of the slider would determine the PWM value to be send to the receiver. I want to control an RGB strip on the recevier from my pi gateway. I used the struct send and receive examples which work fine when broadcasting but how do i send it from a metric in the RPi Gateway.

I also saw that the Broadcast messaging from the PiGateway.ino is disabled. Is there a specific reason for that? As i have for my project multiple RGB receivers which i would like to control at the same time and broadcast would be my choice.

I hope you can help me!
Greetings
Jorg Muskens
The Netherlands
The best way to get something done is to begin

Felix

Is the slider attached to the Pi or where?
The gateway.js metrics are defined to parse the data coming from the RF network of nodes. But I guess you could attach a slider to the receiving Moteino or even MightyHat and then pass that into the gateway as just another token like key:value where the value would be the slider position perhaps.
Broadcasting was disabled in that sketch for no particular reason, just an example how to filter broadcasting was given. If you want to use that and your nodes are coded to respond accordingly then you can use broadcasting.

jorgmuskens

thanks. I will try to get it working. Will post examples as soon as i succeed.
Broadcast is already working with out problems. I removed the broadcast statement from line 84

if (targetId > 0 && targetId != NODEID && targetId != RF69_BROADCAST_ADDR && colonIndex>0 && colonIndex<4 && inputstr.length()>0)
   
change to

if (targetId > 0 && targetId != NODEID &&  colonIndex>0 && colonIndex<4 && inputstr.length()>0)
   
With this change the gateway is able to send broadcast messages.
I only need to figure out how broadcasting works from the Pi server. I will try this tomorrow and report back.

in the meanwhile i also took a look at the gateway.js file and i did find some code that handles the sendmessagetonode (global.sendMessageToNode).
So if i understand this correctly i would put nodeid 255 in the config and the broadcast will be generated on de moteino gateway sketch and send the message to the receivers nodes. Nice!!!

Furthermore i did not try yet to get the slider in the program yet. For now i am just using the + / - buttons to control the value to be send. A slider would be more appropriate. I will try to code this in tomorrow as it is getting late here.

Tx Jorg
The best way to get something done is to begin

jorgmuskens

Hi Felix,
I managed to get the sliders to work with my RGBMote. I am still doing some clean up work in the files which is more like finetuning the code to have it perform the way i want it to.
But here is what i have done to get the sliders to work. In the attachment a screenshot of my RGBMote details page with the actual sliders

I added the following in the <metrics.js> file
exports.metrics = {
  //RGBMote
  RED   : { name:'RED', regexp:/5\:([\d\.]+)/i, value:'', unit:':RED', pin:1, graph:1, graphOptions:{ legendLbl:'RED', lines: { lineWidth:1 }}},
  BLUE  : { name:'BLUE', regexp:/6\:([\d\.]+)/i, value:'', unit:':BLUE', pin:1, graph:1, graphOptions:{ legendLbl:'BLUE', lines: { lineWidth:1 }}},
  START : { name:'UNISWITCH', regexp:/RGBON/i, value:'Started', pin:1},


exports.events = {
  RGBON : { label:'Uniswitch Startup Event', icon:'action', descr:'Send latest RGB values to receiver on startup', 
  	serverExecute:function(node) { 
		if (node.metrics['UNISWITCH'] && node.metrics['UNISWITCH'].value == 'Started' && (Date.now() - new Date(node.metrics['UNISWITCH'].updated).getTime() < 2000)) 
			{ sendMessageToNode({nodeId:node._id, action:'PRG 5:' + node.metrics['RED'].value + ' 6:' + node.metrics['BLUE'].value}); 
		}; 
	} 
  },

exports.motes = {
  RGBMote: {
    label  : 'RGBMote',
    icon   : 'icon_default.png',
    controls : { RED : { states: [{ type:'SLIDER', label:'SET RED VALUE', action:'' }]},
                 BLUE : { states: [{ type:'SLIDER', label:'SET BLUE VALUE', action:'' }]},
		 SENDVALUES : { states: [{ label:'SEND VALUES', action:'STATUS', icon:'action' }], breakAfter:true},
		 GET : { states: [{ label:'GET', action:'STATUS', icon:'refresh' }]},
                 PUSH : { states: [{ label:'PUSH', icon:'arrow-u', serverExecute:function(node) { sendMessageToNode({nodeId:node._id, action:'PRG 5:' + node.metrics['RED'].value + ' 6:' + node.metrics['BLUE'].value});},}]},
    		 RESTART : { states: [{ label:'RESTART', action:'RESTART', icon:'power' }]},
    },
  },


for the exports.motes function i introduced a new state to the control named 'type'. This handles the switch statement in my javascript in the index.html file.
With this i can control what kind of control i want to have on the page. So anything would be possible !?

For the <index.html> file I changed the following
84:   //.center-wrapper * { margin: 0 auto; }
88:   //.ui-slider { width: 10em !important; }

868:
//if btn
	    switch (state.type)
	    {
	    case 'SLIDER':
              var newBtn = $('<div class="ui-field-contain"><label for="slider-'+cKey+'" style="text-align:left;" class="labelbold">'+state.label+'</label><input type="range" name="slider-'+cKey+'" id="slider-'+cKey+'" value="0" min="0" max="255"></div>');
              if (state.css) newBtn.attr('style',state.css);              
              $('#nodeControls').append(newBtn); ////$('#nodeControls').controlgroup("container").append(newBtn);
              break;
            default:  
              var newBtn = $('<a href="#" data-role="button" class="ui-btn ui-btn-inline ui-shadow ui-corner-all">'+state.label+'</a>');
              if (state.css) newBtn.attr('style',state.css);
              if (state.icon)
              {
                newBtn.addClass('ui-btn-icon-left');
                newBtn.addClass('ui-icon-' + state.icon);
              }

              newBtn.bind('click', {nodeId:node._id, action:state.action, nodeType:node.type, cKey:cKey, sKey:sKey}, function(event) {
                //alert(event.data.action + ' was clicked for node ' + event.data.nodeId);
                socket.emit("CONTROLCLICK", {nodeId:event.data.nodeId, action:event.data.action, nodeType:event.data.nodeType, controlKey:event.data.cKey, stateKey:event.data.sKey});
              });
              $('#nodeControls').append(newBtn); ////$('#nodeControls').controlgroup("container").append(newBtn);
	    }
//end switch

905: $("#nodeControls").trigger('create');


The numbers refer to the rows in the file.
for row 84&88 i excluded these because of a style issue with the slider
at row 868 i took the instruction for creating the button and wrapped it in a switch case which checks the state.type from the metrics file. Here i handle which kid of control i want for now i only want a slider.
at row 905 i uncommented the line so each time the page updates the control is rebuild by Jquery. If not the control after the pages refreshes loses it's jquery class.

The only thing i am stuck at is how to set the slider position from the incoming data. Perhaps you have an idea how this can be performed?

The button SEND VALUES actually send the values from the sliders to my MoteIno. As for the sliders they have no actions bind. I did some testing with the CHANGE event but this causes the PiGateway to hang. I think this has to do with the amount of data send for every change in the slider position.

Regards Jorg Muskens
The best way to get something done is to begin

Felix

Very nice work, congrats  8)
I like the sliders and the concept. This could be used for a lot of things. Maybe even set things like the thermostat temperature to a custom value or dim lights etc.
I haven't used jquery mobile sliders before, but I'm sure it's not hard to preset a value for them. Just the same way as I set a value/color for buttons when I create them.
As far as using the sliders directly instead of using a SEND button, you could hook into the onChange (or whatever the appropriate event is) and set a timeout callback at a certain interval (say 500ms or 1sec or whatever). As long as the slider keeps changing the timeout callback is reset to that 1sec. When it expires it sends the action value. That would eliminate the SEND button.
It's just a thought, i hope it helps.
Thanks for sharing your mods!

jorgmuskens

Hi Felix,
i did some more work on the slider control. The problem I was facing is that I wanted the slider to be updated automatically and hold the incoming metric values.
In my first example code above the control is on each refresh recreated by the line item 905 in index.html
$("#nodeControls").trigger('create');

So i changed the index.html a little bit and moved the metriclist refresh blok of code  to the end of the instruction. With this the slider value is set after the slider control is created. 

$('#metricList').empty();
		for(var key in node.metrics)
		{
			var metric = node.metrics[key];
			var metricValue = metricsValues([metric]);
			var newLI = $('<li id="' + key + '"><a metric-id="' + key + '" href="#metricdetails" class="metricdetails"><img class="ui-li-icon" src="images/' + (metric.pin==1 ? 'pin.png' : 'blank.png') + '" />' +  metric.label + ' ' + (metric.graph==1 ? '<img style="width:16px" src="images/graph.png" /> ' : '') + ago(metric.updated, 0).tag + '<span class="ui-li-count ui-li-count16">' + metricValue +  '</span></a></li>');
			$('#metricList').append(newLI);
			switch (metric.label)
			{
				case 'RED':
					$("#slider-RED").val(metric.value).slider('refresh');
					break;
				case 'BLUE':
					$("#slider-BLUE").val(metric.value).slider('refresh');
					break;
			}
			
			if (key == selectedMetricKey)
			{
			  $('.metricUpdated').html(ago(metric.updated, 0).tag);
			  $('#metricValue').val(metric.value + (metric.unit || ''));
			  if (metric.graph) addGraphDataPoint([(new Date()).getTime(), metric.value]); //TODO: assumes same timezone as server, update this according to timezone
			}
		}
		$('#metricList').listview().listview('refresh');
 

I also added a switch statement to dynamically update both sliders. These are now hard coded but with some more work they could be programmed more smartly.
For me they are fine now.

I will continue to work on the onChange event.

Attached are the files I am currently using.
The best way to get something done is to begin

Felix

Thanks very much, a good asset for sure.
If you use github you can push commits to my repository and I can merge them. Something to consider...