419220 (3) [Avatar] Offline
#1
Hi all,
I have a button on my Wot RPi server and have the LED turning on at button push and off at button release.

How I want the LED to toggle on button push. I tried this in node-red and get rapid events (event for button push and event for led state change which sends a http request to the WoT server which creates a new event which goes on and on till I stop the WoT server.)

My question from a philosophical point of view under the 'Web Thing Model' is where should this toggle code be put? In a mashup or in the WoT server (adding a third state to the LEDs called Toggle)?

If I put this code in the mashup I need to find a way of getting the LEDs state with out creating an event or stopping that event at LED change.

Any comment to the first question would be appreciated. I think I can find an answer to the second question.

Mark
Vlad Trifa (16) [Avatar] Offline
#2
Hello there, it's a good question and I don't think there's a right answer or a wrong one. It's ok to add a toggle to the LED in the server (as long as you can change it via a PUT and not a GET - in which case you can read it like any other resource with a GET without changing its state), but it just adds more complex logic on the device (which may or may not be an issue).

I think the real question is as follows: if your device will be a commercial product and this "mini-mashup" is something that will be used commonly by all users of the product (ie it's a function of the device), then it makes perfect sense to put it on the device. If it's an additional specific function that isn't part of the product then it might be better to put it in a mashup in the cloud.

To give an example: if you sell a programmable robot that can do lots of things, the api should support raw access to the motors and mashups would live outside the device. But if you sell a robot that does laundry, the api should have those higher functions (pick shirt, start washing machine, etc.) directly built-in, otherwise it'll be a pain to do that via the raw API - because the function of the robot is to do the laundry, not move motors. Hope this makes sense?

I hope this answers your question, if not feel free to give us more details and we'll try to answer accordingly. Best, Vlad
419220 (3) [Avatar] Offline
#3
thanks for the responce vlad,
I got both versions to work of Toggling (in LED plugin and node-red mashup) to work so readers can take there choice.

LED plugin Toggle,
I modifeid resources/piNoLd.json and plugins/internal/ledsPlugin.js. First piNoLd.json under actions;

"ledState": {
"name": "Change LED state",
"description": "Change the state of an LED",
"values": {
"ledId": {
"type": "enum",
"enum":{"1":"LED 1","2":"LED 2","ALL":"All LEDs"},
"required": true
},
"state": {
"type": "boolean",
"required": true
}
}

change to

"ledState": {
"name": "Change LED state",
"description": "Change the state of an LED",
"values": {
"ledId": {
"type": "enum",
"enum":{"1":"LED 1","2":"LED 2","ALL":"All LEDs"},
"required": true
},
"state": {
"type": "enum",
"enum":{"0":"False","1":"True","2":"Toggle"},
"required": true
}
}

This adds the state 'Toggle' to the LED.

In ledsPlugin.js at the 'function switchOnOff(value)';

function switchOnOff(value) {
var self = this;
if (!this.params.simulate) {
actuator.write(value.state === true ? 1 : 0, function () {
self.addValue(value.state); //#D
});
} else {
self.addValue(value.state);
}
value.status = 'completed'; //#E
console.info('Changed value of %s to %s', self.model.name, value.state);
};


change to

function switchOnOff(value) {
var self = this;
if (!this.params.simulate) {
if (value.state == 0) {
actuator.write(0, function () {
self.addValue(false); //#D
});
}
if (value.state == 1) {
actuator.write(1, function () {
self.addValue(true); //#D
});
}
if (value.state == 2) {
// get LED 1 state
var tempstate = JSON.stringify(util.inspect(this.model.data[this.model.data.length-1])).substring(8,12);
//var tempstate2 = JSON.stringify(util.inspect(this.model.data[this.model.data.length-1]));
//console.info('LED 1 state value of %s to %s', self.model.name, tempstate2);
if (tempstate == 'true') { // 'actuator.readSync() == 1' can be used here
actuator.write(0, function () {
self.addValue(false); //#D
});
} else {
actuator.write(1, function () {
self.addValue(true); //#D
});
}
}
} else {
self.addValue(value.state);
}
value.status = 'completed'; //#E
console.info('Changed2 value of %s to %s', self.model.name, value.state);
};

now sending a state = 2 to LED 1 will Toggle it.


for the mashup in node-red;

In this node-red mashup I created two functions;

inside the first function node is

global.set("led","1"); // this is now available to other nodes

var LEDstate = JSON.parse(msg.payload);

if (LEDstate[1] === true) {

global.set("led","0");

}

This function listens for LED state and sets global LED state, does not pass event


inside the second function node is

msg.headers = {

'Accept' : 'application/json',

'Content-Type' : 'application/json'

}

var myLED = global.get("led"); // read global led state

var button = JSON.parse(msg.payload);

if(button.Push === true) {

msg.payload = {'ledId' : 1, 'state' : myLED};

msg.globalState = myLED;

return msg;

}

This function listens for button push and reads global LED state, pass event to http request node

I will be watching for questions on this subject so try it and ask.


node-red export
[{"id":"d41fdca.d16f4a","type":"function","z":"fff80baf.358058","name":"Create JSON","func":"msg.headers = {\n 'Accept' : 'application/json',\n 'Content-Type' : 'application/json'\n}\nvar myLED = global.get(\"led\"); // read global led state\nvar button = JSON.parse(msg.payload);\nif(button.Push === true) {\n msg.payload = {'ledId' : 1, 'state' : myLED};\n msg.globalState = myLED;\n return msg;\n}","outputs":"1","noerr":0,"x":358,"y":140,"wires":[["f90c301c.8dbad8","8fdaec34.137378","3c7bf0c7.568858"]]},{"id":"8fdaec34.137378","type":"http request","z":"fff80baf.358058","name":"","method":"POST","ret":"obj","url":"http://192.168.137.10:8484/actions/ledState","tls":"","x":548,"y":140,"wires":[[]]},{"id":"9a109765.85e258","type":"websocket in","z":"fff80baf.358058","name":"Listen for Button","server":"","client":"6b2b4468.64ed54","x":124,"y":135,"wires":[["d41fdca.d16f4a","6690cae6.da9f0c"]]},{"id":"bef12b6a.ec0838","type":"comment","z":"fff80baf.358058","name":"Listen for Button","info":"Listen for Button at \nws://192.168.137.10:8484/properties/leds\nthen read global LED state\nthen request post to \nhttp://192.168.137.10:8484/actions/ledState","x":191,"y":75,"wires":[]},{"id":"f90c301c.8dbad8","type":"debug","z":"fff80baf.358058","name":"","active":true,"console":"false","complete":"false","x":562,"y":215.5,"wires":[]},{"id":"6690cae6.da9f0c","type":"debug","z":"fff80baf.358058","name":"","active":true,"console":"false","complete":"false","x":321,"y":214.5,"wires":[]},{"id":"7324ae14.a84458","type":"websocket in","z":"fff80baf.358058","name":"LED state","server":"","client":"4fe7bdea.824c1c","x":106,"y":316.5,"wires":[["be8f410d.7eb998"]]},{"id":"be8f410d.7eb998","type":"function","z":"fff80baf.358058","name":"set Global led","func":"global.set(\"led\",\"1\"); // this is now available to other nodes\nvar LEDstate = JSON.parse(msg.payload);\nif (LEDstate[1] === true) {\n global.set(\"led\",\"0\");\n}","outputs":1,"noerr":0,"x":303,"y":316.5,"wires":[[]]},{"id":"3c7bf0c7.568858","type":"debug","z":"fff80baf.358058","name":"","active":true,"console":"false","complete":"globalState","x":554,"y":290.5,"wires":[]},{"id":"6b2b4468.64ed54","type":"websocket-client","z":"fff80baf.358058","path":"ws://192.168.137.10:8484/properties/button","wholemsg":"false"},{"id":"4fe7bdea.824c1c","type":"websocket-client","z":"fff80baf.358058","path":"ws://192.168.137.10:8484/properties/leds","wholemsg":"false"}]

domguinard (69) [Avatar] Offline
#4
Hi Mark,

This is great, thanks a lot for sharing the code, we'll include it in the next releases if you don't mind.
419220 (3) [Avatar] Offline
#5
Quote for 'Apache License'
Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.

This should work for a while. When we humans get to the moon I can see this license needing modification.