I can change it back to a 1.5.* code. It'll be a day or so, as I'm busy right now (homework, etc).
Posts made by cranky
-
RE: FastLED / Neopixel (ws2811) Node, From Arduino code to Web page (with API)
-
RE: ioBroker = Home automation/Node ALL in ONE/ for noobs https +Let's encrypt/MQTT/Node Red/
I'm honestly torn on making Windows/Linux programs. I certainly get the idea why you would want something like that, but I'd much rather have an HTML5 website that does that instead of an x86 program...
Web browsers are on everything, whereas the idea of fat binaries is still a very rare one.
My underlying works revolve in making web APIs, so I can create websites and scripts that can do "stuff" without me even hitting buttons.
For example, I'd like to have an IoT doorbell. Simple. When it triggers, a flow interrogates if there is anybody in the house. If yes, ring the doorbell. Also, when doorbell is triggered, take a photo from the door and run it through a facial recognizer and send to me.
... And that's just a doorbell.
-
RE: Flow to turn SerialGateway into MQTT-SerialGateway
Ok, as you saw, I got the MQTT<-->TCP connector done , and that's live
Now, I have my GH up and populated. It's pretty sparse with documentation right now, but that will change.
https://github.com/jwcrawley/node-red-mysensors-flows/What's cool is I can use a the "Watch" NR node and watch for updates in my working directory and auto-push
All you need is your SSH keys set up.
Then you watch for /.git/COMMIT_EDITMSG and when a change hits that, do a
git add (repo directory)
Then read the /.git/COMMIT_EDITMSG into msg.payload and then send it to an EXEC node as
git commit -m {{payload}}
And then
git push origin master
..... And there you have it: automated local to Github.
-
RE: Windows GUI/Controller for MySensors
@tekka You might not have to. I've been working on Node-Red as a controller and more.
With my kit, you need Node-Red, node-red-contrib-mysensors , Mosquitto, and some of my flows which I have available ( http://forum.mysensors.org/topic/2802/flow-to-turn-serialgateway-into-mqtt-serialgateway ).
And it makes this:
http://forum.mysensors.org/topic/2815/flow-to-turn-serialgateway-with-mqtt-flow-to-ethernetgatewayThe only flaw is that when you first connect MYSController, you need to send a junk topic so that MYSController can receive data. It's a bug/peculiarity with Node-Red, but honestly not a big deal. I'm also working on how to fix even that.
-
RE: "Sketch Time" (I_TIME) Handler
Ah cool So yes, make the user do it. I like the sound of that.
Time stinks. Only thing I can say about that is, "Never again."
-
RE: "Sketch Time" (I_TIME) Handler
Really? I'd rather handle absolute time of "Seconds since the Epoch". If you use that, there's no reason or need to mess with DST, time zones, or anything else. It's only when you convert "Seconds Since Epoch"->"String of Current time/date" do you get into having to deal with TZdata and all that garbage.
Then, on the local device, the user can bake in the Arduino sketch the timezone they are using. Of course, then they have to deal with the horrors of DST and timezones... that is if they want to.
I log most of my data in seconds(or ms) since epoch. All my logs are then completely synchronized, as much as an NTP client can manage.
Sincerely,
Cranky -
Flow to turn SerialGateway with MQTT-FLOW to EthernetGateway
Whew. This is a hard one, and not completely debugged. But as of right now, I can receive and send data through MYSController!
You will need:
http://forum.mysensors.org/topic/2802/flow-to-turn-serialgateway-into-mqtt-serialgateway
mosquitto MQTT broker (server)
node-red-contrib-mysensors
download of MYSControllerWhat you get:
Serial communication (duh!)
MQTT communication
TCP server that MYSController speaks ------ WOOT
~and you can connect as many clients to this TCP server as you want O_oThe current topology is that I'm using a SerialGateway. All data to and from this goes into a Mosquitto MQTT broker. From then on, I only work with the broker, and not serial ports.
This flow is the same: this should work with any MQTT implementation. Do note, my root topic is named MySensors/ . If yours is different, you will have to find and replace in my code.
And yes, MYSController works well on WINE
KNOWN BUG: Because of the way Node-Red tracks connections, you MUST send a packet from MYScontroller after connecting in order to capture the session. From then on, everything will work. If you do not do this, then you will not be able to receive any data in MYSController.
[{"id":"72a5a797.020098","type":"mqtt-broker","z":"b2cff5f2.9cc8b","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"5d726ee1.43674","type":"mqtt-broker","z":"316a4c44.7a9114","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"e7324836.248338","type":"mqtt in","z":"316a4c44.7a9114","name":"","topic":"MySensors/#","broker":"5d726ee1.43674","x":80,"y":216,"wires":[["a009a85d.aa4b58"]]},{"id":"a009a85d.aa4b58","type":"function","z":"316a4c44.7a9114","name":"MQTT to MYS Serial","func":"var splitTopic= msg.topic.split(\"\\/\");\n\n// splitTopic[0] is the MySensors/ preamble. #1 is NODE_ID and on up. \nmsg.payload = splitTopic[1] + \";\" + splitTopic[2] + \";\" + splitTopic[3] + \";\" + splitTopic[4] + \";\" + splitTopic[5] + \";\" + msg.payload ;\nreturn msg;","outputs":1,"noerr":0,"x":260,"y":216,"wires":[["87d95f68.d5bf28"]]},{"id":"61cc3040.0a2ce","type":"mqtt out","z":"316a4c44.7a9114","name":"To MQTT","topic":"","qos":"","retain":"","broker":"72a5a797.020098","x":700,"y":148,"wires":[]},{"id":"57b96ecb.e396f","type":"mysdecenc","z":"316a4c44.7a9114","name":"","x":340,"y":148,"wires":[["2d0808fa.b5f988"]]},{"id":"2d0808fa.b5f988","type":"function","z":"316a4c44.7a9114","name":"Formats MQTT topic","func":"msg.topic = \"MySensors\" + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.messageType + \"/\" + msg.ack + \"/\" + msg.subType;\nreturn msg;","outputs":1,"noerr":0,"x":525,"y":148,"wires":[["61cc3040.0a2ce"]]},{"id":"172ecad5.7d5e7d","type":"debug","z":"316a4c44.7a9114","name":"","active":true,"console":"false","complete":"true","x":568,"y":287,"wires":[]},{"id":"e374dc2e.759fe8","type":"tcp out","z":"316a4c44.7a9114","host":"","port":"","beserver":"reply","base64":false,"end":false,"name":"","x":560,"y":218,"wires":[]},{"id":"d8774c60.3e3718","type":"tcp in","z":"316a4c44.7a9114","name":"","server":"server","host":"","port":"5003","datamode":"stream","datatype":"utf8","newline":"\\n","topic":"","base64":false,"x":76,"y":146,"wires":[["2cdfadb8.70f112","73ae599e.322238"]]},{"id":"2cdfadb8.70f112","type":"debug","z":"316a4c44.7a9114","name":"","active":true,"console":"false","complete":"true","x":218,"y":89,"wires":[]},{"id":"73ae599e.322238","type":"function","z":"316a4c44.7a9114","name":"","func":"context.global.tcpsess = context.global.tcpsess || msg._session;\nreturn msg;","outputs":1,"noerr":0,"x":204,"y":147,"wires":[["57b96ecb.e396f"]]},{"id":"87d95f68.d5bf28","type":"function","z":"316a4c44.7a9114","name":"","func":"msg._session = context.global.tcpsess;\nreturn msg;","outputs":1,"noerr":0,"x":432,"y":217,"wires":[["e374dc2e.759fe8","172ecad5.7d5e7d"]]}]
-
RE: Flow to turn SerialGateway into MQTT-SerialGateway
Unfortunately, I do not. Until when I just looked at the source "MyGatewayTransportEthernet.cpp", I mistakenly assumed that it too published to an MQTT broker.
It doesn't look too terribly hard to do; with UDP being easier. But my main caveat here is that I don't have an SPI ethernet port for an arduino. That means I wouldn't be able to test my code.
If there was a packet documentation for TCP and UDP, I could write code for the reference. Again, past library and serial documentation, there is none I can refer to.
Of if some hardware fairy would be willing to send me a compatible SPI ethernet port, I could do it
documentation
MY_PORT = (default) 5003
(TCP/UDP) choice
(server mode / client mode) choice. IP dest. reqd for being client
buffer receiving: 100 B
buffer sending: 120 B -
RE: "Sketch Config" (I_CONFIG) Handler
Not yet, but that was my goal tomorrow.
My GH account is https://github.com/jwcrawley
It'll be obvious when I add in the repo I'll also mention it here.
Sincerely,
Cranky -
"Sketch Config" (I_CONFIG) Handler
This flow takes care of the challenge/response for when a sensor asks what config to use (Metric or imperial).
By default, the code returns M for metric. I don't believe Imperial is used anywhere, but it can be changed to I... if you support it in your code. (Honestly, no clue, but some sketches do make use of the call getConfig() .)
[{"id":"8e3e8f02.7fd0c","type":"mqtt-broker","z":"63842e72.893f78","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"57ad0c01.895c9c","type":"mqtt in","z":"63842e72.893f78","name":"Sensor Requests Config","topic":"MySensors/+/255/3/0/6","broker":"8e3e8f02.7fd0c","x":105,"y":993,"wires":[["cd60b38.ef7405"]]},{"id":"86a8016b.bd47a","type":"mqtt out","z":"63842e72.893f78","name":"","topic":"","qos":"","retain":"","broker":"8e3e8f02.7fd0c","x":672,"y":993,"wires":[]},{"id":"65a6cc53.392ccc","type":"function","z":"63842e72.893f78","name":"Metric/Imperial definition","func":"var config = \"M\" ; //M for metric, and I for imperial\n\nmsg.payload = config + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":488,"y":993,"wires":[["86a8016b.bd47a","165c11cd.40adbe"]]},{"id":"165c11cd.40adbe","type":"debug","z":"63842e72.893f78","name":"","active":true,"console":"false","complete":"false","x":692,"y":952,"wires":[]},{"id":"cd60b38.ef7405","type":"delay","z":"63842e72.893f78","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":295,"y":993,"wires":[["65a6cc53.392ccc"]]},{"id":"9687065f.28c08","type":"comment","z":"63842e72.893f78","name":"I_CONFIG handler ([0-255];255;3;0;6;[M or I])","info":"Whenever a sensor announces itself to the network as [any];255;3;0;6;(null),\n\nThe cntroller returns a M for metric or I for imperial. \nTo my understanding, imperial measurement reportings aren't used.\n\n\nA rate limiter was required as to keep NR and the sensor from a spam-loop","x":298,"y":1030,"wires":[]}]```
-
"Sketch Time" (I_TIME) Handler
This flow takes care of the I_TIME call made to the gateway.
The confusing part about this Internal call is: do we return UTC, or local time? It would be trivial to have a sensor pass as
[id];255;3;0;1;(timezone)
rather than
[id];255;3;0;1;\n
so that Time local to where the sensor was placed could be recorded. The only caveat is that DST would mess it up... However, since the Arduino sketch "Time Aware Sensor" polls the gateway every hour for time, at most your logs/data will be off by at most 1 hour. This can easily be changed to the tolerance your need desires.
[{"id":"8e3e8f02.7fd0c","type":"mqtt-broker","z":"63842e72.893f78","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"71e13b71.966fa4","type":"mqtt in","z":"63842e72.893f78","name":"Sensor Requests Time ","topic":"MySensors/+/255/3/0/1","broker":"8e3e8f02.7fd0c","x":102,"y":852,"wires":[["24b5e719.a8a1d8"]]},{"id":"92a5ad9d.a8b328","type":"function","z":"63842e72.893f78","name":"seconds since epoch","func":"var timezone_offset = -5 // As hours against UTC\n\nmsg.payload = Math.floor( Date.now() / 1000 ); // seconds since jan 1 1970\nmsg.payload = msg.payload + ( timezone_offset * 3600);\nreturn msg;","outputs":1,"noerr":0,"x":465,"y":851,"wires":[["b7cc49b4.1520c8","4686a23a.28493c"]]},{"id":"b7cc49b4.1520c8","type":"mqtt out","z":"63842e72.893f78","name":"Time to Topic","topic":"","qos":"","retain":"","broker":"8e3e8f02.7fd0c","x":657,"y":850,"wires":[]},{"id":"e059f1d.9421f1","type":"comment","z":"63842e72.893f78","name":"I_TIME handler ([0-255];255;3;0;1;[sec since epoch])","info":"Whenever a sensor announces itself to the network as [any];255;3;0;1;(null),\nit returns to the same topic the amount of seconds since Jan 1 1970 (also called Epoch)\n\nA rate limiter was required as to keep NR and the sensor from a spam-loop","x":301,"y":899,"wires":[]},{"id":"4686a23a.28493c","type":"debug","z":"63842e72.893f78","name":"","active":false,"console":"false","complete":"false","x":642,"y":817,"wires":[]},{"id":"24b5e719.a8a1d8","type":"delay","z":"63842e72.893f78","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":284,"y":852,"wires":[["92a5ad9d.a8b328"]]},{"id":"46b988b9.969a88","type":"comment","z":"63842e72.893f78","name":"Change timezone here","info":"","x":450,"y":818,"wires":[]}]
-
"Sketch Version" (I_SKETCH_VERSION) Handler
I extended the /root/leases.file to also include a 3rd field for version. Now you can update nodes and see the version change as you update (or view unupdated ones).
It is functionally very similar to that of I_SKETCH_NAME handler.
[{"id":"8e3e8f02.7fd0c","type":"mqtt-broker","z":"63842e72.893f78","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"21742d0e.25817a","type":"mqtt in","z":"63842e72.893f78","name":"Rename sensor in file","topic":"MySensors/+/255/3/0/12","broker":"8e3e8f02.7fd0c","x":106,"y":630,"wires":[["8a1e6bb3.db726"]]},{"id":"8a1e6bb3.db726","type":"function","z":"63842e72.893f78","name":"message to edit","func":"var splitTopic= msg.topic.split(\"\\/\");\nmsg.payload = msg.payload.replace(\"\\n\", \"\");\nmsg.edit = {col1:splitTopic[1] , col3:msg.payload}; \n// msg.edit carries over the next 2 nodes to \"find edit and replace\" function node\nreturn msg;","outputs":1,"noerr":0,"x":352,"y":629,"wires":[["cb5f1a37.6ab65"]]},{"id":"cb5f1a37.6ab65","type":"file in","z":"63842e72.893f78","name":"","filename":"/root/leases.file","format":"utf8","x":528,"y":630,"wires":[["77038207.b61144"]]},{"id":"77038207.b61144","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"mult","ret":"\\n","temp":"col1,col2,col3","x":113,"y":701,"wires":[["f2858e20.0e9b18"]]},{"id":"f2858e20.0e9b18","type":"function","z":"63842e72.893f78","name":"find edit and replace","func":"for(var i = 0; i < msg.payload.length; i++){\n if( msg.edit.col1 == msg.payload[i].col1 ){\n msg.payload[i].col3 = msg.edit.col3;\n }\n}\nreturn msg;","outputs":1,"noerr":0,"x":282,"y":701,"wires":[["2ef32bcf.fefb74"]]},{"id":"321725f3.9ad162","type":"file","z":"63842e72.893f78","name":"","filename":"/root/leases.file","appendNewline":true,"createDir":false,"overwriteFile":"true","x":644,"y":702,"wires":[]},{"id":"6404769b.fdaff8","type":"debug","z":"63842e72.893f78","name":"","active":true,"console":"false","complete":"false","x":634,"y":741,"wires":[]},{"id":"2ef32bcf.fefb74","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"one","ret":"\\n","temp":"col1,col2,col3","x":449,"y":701,"wires":[["321725f3.9ad162","6404769b.fdaff8"]]},{"id":"aaea7f9c.a0adf","type":"comment","z":"63842e72.893f78","name":"I_SKETCH_VERSION handler ([0-255];255;3;0;12;[name])","info":"Whenever a sensor announces itself to the network as [any];255;3;0;11;[name from presentation],\nit modifies field 2 for that appropriate sensor. \n\nThe resulting modification is then saved.","x":304,"y":743,"wires":[]}]
-
RE: "Sketch Name" (I_SKETCH_NAME) Handler
Debugged, changelog 13 jan2016.
Added 3rd field, for version. Fixed \n being passed and messing up CSV file.
[{"id":"8e3e8f02.7fd0c","type":"mqtt-broker","z":"63842e72.893f78","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"2b18ee58.b63042","type":"mqtt in","z":"63842e72.893f78","name":"Rename sensor in file","topic":"MySensors/+/255/3/0/11","broker":"8e3e8f02.7fd0c","x":147,"y":347,"wires":[["34a4252.48ed9da"]]},{"id":"34a4252.48ed9da","type":"function","z":"63842e72.893f78","name":"message to edit","func":"var splitTopic= msg.topic.split(\"\\/\");\nmsg.edit = {col1:splitTopic[1] , col2:msg.payload}; \n// msg.edit carries over the next 2 nodes to \"find edit and replace\" function node\nreturn msg;","outputs":1,"noerr":0,"x":349,"y":346,"wires":[["2032129a.b17cfe"]]},{"id":"2032129a.b17cfe","type":"file in","z":"63842e72.893f78","name":"","filename":"/root/leases.file","format":"utf8","x":525,"y":347,"wires":[["2c70d9c7.e8d2ee"]]},{"id":"2c70d9c7.e8d2ee","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"mult","ret":"\\n","temp":"col1,col2,col3","x":110,"y":418,"wires":[["f17d2f12.1254c8"]]},{"id":"f17d2f12.1254c8","type":"function","z":"63842e72.893f78","name":"find edit and replace","func":"for(var i = 0; i < msg.payload.length; i++){\n if( msg.payload[i].col1 == msg.edit.col1 ){\n msg.payload[i].col2 = msg.edit.col2;\n return msg;\n }\n if( msg.payload[i].col1 > msg.edit.col1 ){\n msg.payload.splice(i,0, {col1: (i-1), col2: msg.edit.col2, col3: \"\"}) ;\n }\n}\nreturn msg;","outputs":1,"noerr":0,"x":279,"y":418,"wires":[["c2871f53.c8caa"]]},{"id":"55feab8a.9176ac","type":"file","z":"63842e72.893f78","name":"","filename":"/root/leases.file","appendNewline":true,"createDir":false,"overwriteFile":"true","x":641,"y":419,"wires":[]},{"id":"7263dd71.ca4b94","type":"debug","z":"63842e72.893f78","name":"","active":true,"console":"false","complete":"false","x":631,"y":458,"wires":[]},{"id":"c2871f53.c8caa","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"one","ret":"\\n","temp":"col1,col2,col3","x":446,"y":418,"wires":[["55feab8a.9176ac","7263dd71.ca4b94"]]},{"id":"852f49a7.0d18c","type":"comment","z":"63842e72.893f78","name":"I_SKETCH_NAME handler ([0-255];255;3;0;11;[name])","info":"Whenever a sensor announces itself to the network as [any];255;3;0;11;[name from presentation],\nit modifies field 2 for that appropriate sensor. \n\nThe resulting modification is then saved.","x":310,"y":456,"wires":[]}]
-
RE: Can not see my Humidity sensor
If you open up a serial console with the SerialGateway, you can respond with the following
255;255;3;0;4;[ID you want it to have]
And then the ID will be copied into EEprom on the sensor and then work as that ID number you assign it.
-
"Sketch Name" (I_SKETCH_NAME) Handler
This is to be used in conjunction with:
http://forum.mysensors.org/topic/2803/dhcp-i_id_request-handler
http://forum.mysensors.org/topic/2802/flow-to-turn-serialgateway-into-mqtt-serialgateway
... As well as have a file "/root/leases.file" be readable/writable from your node-red user.This flow relabels the sensors in your sensor lease file to the correct name you provided in the Presentation section of your arduino code. The file, /root/leases.file is a simple CSV file. column 1 is ID and column 2 is sensor_name
I usually run the "DHCP" and this script on the same flow sheet.
[{"id":"8e3e8f02.7fd0c","type":"mqtt-broker","z":"63842e72.893f78","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"2b18ee58.b63042","type":"mqtt in","z":"63842e72.893f78","name":"Rename sensor in file","topic":"MySensors/+/255/3/0/11","broker":"8e3e8f02.7fd0c","x":147,"y":347,"wires":[["34a4252.48ed9da"]]},{"id":"34a4252.48ed9da","type":"function","z":"63842e72.893f78","name":"message to edit","func":"var splitTopic= msg.topic.split(\"\\/\");\nmsg.edit = {col1:splitTopic[1] , col2:msg.payload}; \n// msg.edit carries over the next 2 nodes to \"find edit and replace\" function node\nreturn msg;","outputs":1,"noerr":0,"x":349,"y":346,"wires":[["2032129a.b17cfe"]]},{"id":"2032129a.b17cfe","type":"file in","z":"63842e72.893f78","name":"","filename":"/root/leases.file","format":"utf8","x":525,"y":347,"wires":[["2c70d9c7.e8d2ee"]]},{"id":"2c70d9c7.e8d2ee","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"mult","ret":"\\n","temp":"","x":110,"y":418,"wires":[["f17d2f12.1254c8"]]},{"id":"f17d2f12.1254c8","type":"function","z":"63842e72.893f78","name":"find edit and replace","func":"for(var i = 0; i < msg.payload.length; i++){\n if( (msg.edit.col1 == msg.payload[i].col1) && (msg.payload[i].col2 == \"temporary\") ){\n msg.payload[i].col2 = msg.edit.col2;\n }\n}\nreturn msg;","outputs":1,"noerr":0,"x":279,"y":418,"wires":[["c2871f53.c8caa"]]},{"id":"55feab8a.9176ac","type":"file","z":"63842e72.893f78","name":"","filename":"/root/leases.file","appendNewline":true,"createDir":false,"overwriteFile":"true","x":641,"y":419,"wires":[]},{"id":"7263dd71.ca4b94","type":"debug","z":"63842e72.893f78","name":"","active":true,"console":"false","complete":"false","x":631,"y":458,"wires":[]},{"id":"c2871f53.c8caa","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"one","ret":"\\n","temp":"col1,col2","x":446,"y":418,"wires":[["55feab8a.9176ac","7263dd71.ca4b94"]]},{"id":"852f49a7.0d18c","type":"comment","z":"63842e72.893f78","name":"I_SKETCH_NAME handler ([0-255];255;3;0;11;[name])","info":"Whenever a sensor announces itself to the network as [any];255;3;0;11;[name from presentation],\nit modifies field 2 for that appropriate sensor. \n\nThe resulting modification is then saved.","x":369,"y":510,"wires":[]}]
-
RE: Flow to turn SerialGateway into MQTT-SerialGateway
Gladly There's more coming out. I just provided the flow to handle "DHCP" sensors (or the ones that do REQ ID 255;255;3;0;3;\n)
One step at a time....
-
"DHCP" (I_ID_REQUEST) Handler
This code is to be used in conjunction of a set up MQTT broker (Mosquitto) and the prior flow listed in "Flow to turn SerialGateway into MQTT-SerialGateway"
This watches all data coming in from topic MySensors/255/255/3/0/3/ and does a lookup in the DB for a new unused ID. Then it assigns the sensors the ID as well as updating the DB.
There may be some bugs, as testing this code requires extra work.
Essentially, in a location in EEprom lives the assigned ID number. So in order to test this, you need to:
load ClearEEPROM sketch. open Serial console and wait till done.
Then load a sketch that doesn't have the Node ID set (#define NODE_ID 1.6 and gw.begin(NULL, AUTO) in 1.5)
Assigning happens once. If messed up, load clearEEPROM and do againBIG NOTE: You do need read/write access to file /root/leases.file from whatever user you are running in Node-Red. I chose /root/leases.file because I wanted it easy to find and of indication that it is an important file. You can change it, but make sure to catch all the file nodes that reference to it.
[{"id":"8e3e8f02.7fd0c","type":"mqtt-broker","z":"63842e72.893f78","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"778435ae.0d9c4c","type":"mqtt in","z":"63842e72.893f78","name":"Incoming DHCP request","topic":"MySensors/255/255/3/+/3","broker":"8e3e8f02.7fd0c","x":112.5,"y":136,"wires":[["c77f47f6.5dcc1"]]},{"id":"c77f47f6.5dcc1","type":"file in","z":"63842e72.893f78","name":"","filename":"/root/leases.file","format":"utf8","x":307,"y":137,"wires":[["a09e2794.97bca8"]]},{"id":"a09e2794.97bca8","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"mult","ret":"\\n","temp":"","x":450,"y":136,"wires":[["f33caa99.b57308"]]},{"id":"f33caa99.b57308","type":"function","z":"63842e72.893f78","name":"Saves and emits assigned ID","func":"var lease = -1 ;\nvar splitString;\n\nfor (var i=0; (i<msg.payload.length) && (lease == -1);i++){\n if(msg.payload[i].col1 != i){\n msg.payload.splice(i,0, {col1: i, col2:\"temporary\"});\n lease = i ;\n }\n}\n\nif (lease == -1){ // means there's no holes in the lease file\n lease = msg.payload.length ;\n msg.payload.push( {col1: lease, col2:\"temporary\"} ); // returns next number in order\n}\n\nvar msg2 = { payload:lease};\n\nreturn [msg, msg2];","outputs":"2","noerr":0,"x":640,"y":136,"wires":[["15c23ce9.f74c03","ccd034fb.54b728"],["50521f88.55082","ccd034fb.54b728"]]},{"id":"15c23ce9.f74c03","type":"csv","z":"63842e72.893f78","name":"","sep":",","hdrin":"","hdrout":"","multi":"one","ret":"\\n","temp":"col1,col2","x":663,"y":96,"wires":[["2092d4a1.661c84"]]},{"id":"2092d4a1.661c84","type":"file","z":"63842e72.893f78","name":"","filename":"/root/leases.file","appendNewline":false,"createDir":false,"overwriteFile":"true","x":670,"y":55,"wires":[]},{"id":"50521f88.55082","type":"mqtt out","z":"63842e72.893f78","name":"","topic":"MySensors/255/255/3/0/4","qos":"","retain":"","broker":"8e3e8f02.7fd0c","x":636,"y":199,"wires":[]},{"id":"ccd034fb.54b728","type":"debug","z":"63842e72.893f78","name":"DHCP result","active":false,"console":"false","complete":"payload","x":865,"y":135,"wires":[]},{"id":"420b8cdd.3a696c","type":"comment","z":"63842e72.893f78","name":"I_ID_REQUEST handler (255;255;3;0;3 , 255;255;3;0;4;[ID])","info":"Beginning listens to messages of 255;255;3;0;3;\\n , which is broadcast request for ID\nLeases file is read, and interpreted as CSV. \nFunction block does 2 things:\n 1. Adds new sensor's ID to lease file\n 2. Sends back to MQTT the ID the device is granted to 255;255;3;0;4;[ID]\\n","x":272,"y":83,"wires":[]}]
-
RE: Flow to turn SerialGateway into MQTT-SerialGateway
@barduino . How peculiar. I think it might be the way RasPi chose to include Node-red. It appears that you might need to do my above npm command with sudo... You shouldn't need to hand-create node_modules or node-red-contrib-mysensors. npm should have done that all for you, along with any potential dependencies. Adafruit's help goes into Pi-weirdness: https://learn.adafruit.com/raspberry-pi-hosting-node-red/installing-further-plugins
But I hope the mysensors removal works well. Like I said, haven't tested it yet
Good luck!
Cranky -
RE: Flow to turn SerialGateway into MQTT-SerialGateway
Oh, it's that error
Delete the sheet, and re-copy. It will show up then. That, btw, is an existing bug in NR.
-
RE: Flow to turn SerialGateway into MQTT-SerialGateway
if you do
npm install node-red-contrib-mysensors
It should work. If it doesn't, can you post the full text of the error please?
Oh, also, I chopped out the requirements for node-red-contrib-mysensors. Now, you should only need Serial, Function, MQTT, and Debug. Try this. Beware, I didn't test it, as I don't have easy remote access to my Broker.
[{"id":"938db5f1.fc32d","type":"mqtt-broker","z":"61b3db25.ac0dcc","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"e8212410.a623d","type":"serial-port","z":"61b3db25.ac0dcc","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"142d3129.87f8a7","type":"debug","z":"61b3db25.ac0dcc","name":"Serial to MQTT debug","active":false,"console":"false","complete":"true","x":791,"y":214,"wires":[]},{"id":"3637dd4b.cb9c4a","type":"serial in","z":"61b3db25.ac0dcc","name":"","serial":"e8212410.a623d","x":255,"y":264,"wires":[["e3ff437d.acd2a"]]},{"id":"40b2ff18.06e41","type":"mqtt in","z":"61b3db25.ac0dcc","name":"","topic":"MySensors/#","broker":"938db5f1.fc32d","x":271.5,"y":324,"wires":[["f638c51f.95fb78"]]},{"id":"f638c51f.95fb78","type":"function","z":"61b3db25.ac0dcc","name":"convert topic to Serial protocol","func":"msg.topic = msg.topic.replace(\"MySensors\\/\", \"\"); // Gets rid of MySensors preamble\nfor (i=0;i<4;i++){\n msg.topic = msg.topic.replace(\"\\/\", \";\");\n}\nmsg.payload = msg.topic + \";\" + msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":490,"y":324,"wires":[["4b33e37a.1bab14","51bc5462.90ca1c"]]},{"id":"4b33e37a.1bab14","type":"debug","z":"61b3db25.ac0dcc","name":"MQTT to Serial debug","active":false,"console":"false","complete":"true","x":756,"y":373,"wires":[]},{"id":"51bc5462.90ca1c","type":"serial out","z":"61b3db25.ac0dcc","name":"","serial":"e8212410.a623d","x":718,"y":323,"wires":[]},{"id":"e6240f60.af5c78","type":"mqtt out","z":"61b3db25.ac0dcc","name":"","topic":"To MQTT","qos":"","retain":"","broker":"938db5f1.fc32d","x":770,"y":264,"wires":[]},{"id":"e3ff437d.acd2a","type":"function","z":"61b3db25.ac0dcc","name":"Formats MQTT topic","func":"var sensor = msg.payload.split(\";\");\nmsg.topic = \"MySensors\" + \"/\" + sensor[0] + \"/\" + sensor[1] + \"/\" + sensor[2] + \"/\" + sensor[3] + \"/\" + sensor[4];\nmsg.payload = sensor[5];\nreturn msg;","outputs":1,"noerr":0,"x":498,"y":265,"wires":[["e6240f60.af5c78","142d3129.87f8a7"]]}]
-
Flow to turn SerialGateway into MQTT-SerialGateway
After installing and working with Mosquitto, I realized that this was going to be easier than implement a SQlite db. However, I already have a SerialGateway and don't have an i2c/spi ethernet device for my microcontrollers. Not a big deal; I have Node-Red.
No, why would I want Mosquitto? It's the MQTT broker, and a really good lean one. The configuration sucks, but time for learning, eh? Ideally, instead of having "In-Serial" and "Out-Serial" littered all around in your code, you can have clear MQTT topic subscriptions and topic outputs in your code.
It also allows you to use other Controllers as well. Let's get started.
- Install Mosquitto for your platform.
- (optional) Configure Mosquitto for security. Login/pass and generate SSL certs. If this is public facing, you will need LetsEncrypt certs for encrypted Websockets
- Node-Red flow:
[{"id":"72a5a797.020098","type":"mqtt-broker","z":"b2cff5f2.9cc8b","broker":"localhost","port":"8883","clientid":"","usetls":false,"verifyservercert":true,"compatmode":true,"keepalive":"15","cleansession":true,"willTopic":"","willQos":"0","willRetain":null,"willPayload":"","birthTopic":"","birthQos":"0","birthRetain":null,"birthPayload":""},{"id":"fe37ebc7.c69d68","type":"serial-port","z":"b2cff5f2.9cc8b","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"1d5d1eec.5b3009","type":"debug","z":"b2cff5f2.9cc8b","name":"Serial to MQTT debug","active":false,"console":"false","complete":"true","x":635,"y":48,"wires":[]},{"id":"6c0c081e.aac08","type":"serial in","z":"b2cff5f2.9cc8b","name":"","serial":"fe37ebc7.c69d68","x":99,"y":98,"wires":[["4f1327d4.d482c"]]},{"id":"88f499d1.fae8c","type":"mqtt in","z":"b2cff5f2.9cc8b","name":"","topic":"MySensors/#","broker":"72a5a797.020098","x":115.5,"y":158,"wires":[["b006de82.c402b"]]},{"id":"b006de82.c402b","type":"function","z":"b2cff5f2.9cc8b","name":"convert topic to Serial protocol","func":"msg.topic = msg.topic.replace(\"MySensors\\/\", \"\"); // Gets rid of MySensors preamble\nfor (i=0;i<4;i++){\n msg.topic = msg.topic.replace(\"\\/\", \";\");\n}\nmsg.payload = msg.topic + \";\" + msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":334,"y":158,"wires":[["3f76ac9e.e553cc","543d809e.d80758"]]},{"id":"3f76ac9e.e553cc","type":"debug","z":"b2cff5f2.9cc8b","name":"MQTT to Serial debug","active":false,"console":"false","complete":"true","x":600,"y":207,"wires":[]},{"id":"543d809e.d80758","type":"serial out","z":"b2cff5f2.9cc8b","name":"","serial":"fe37ebc7.c69d68","x":562,"y":157,"wires":[]},{"id":"f8db4507.4574c8","type":"mqtt out","z":"b2cff5f2.9cc8b","name":"","topic":"To MQTT","qos":"","retain":"","broker":"72a5a797.020098","x":614,"y":98,"wires":[]},{"id":"4f1327d4.d482c","type":"mysdecenc","z":"b2cff5f2.9cc8b","name":"","x":254,"y":98,"wires":[["4fe1aca3.083e44"]]},{"id":"4fe1aca3.083e44","type":"function","z":"b2cff5f2.9cc8b","name":"Formats MQTT topic","func":"msg.topic = \"MySensors\" + \"/\" + msg.nodeId + \"/\" + msg.childSensorId + \"/\" + msg.messageType + \"/\" + msg.ack + \"/\" + msg.subType;\nreturn msg;","outputs":1,"noerr":0,"x":439,"y":98,"wires":[["f8db4507.4574c8","1d5d1eec.5b3009"]]}]
Citation: The MQTT submission format (along with challenge/response network flow) is NOT documented(on library or serial API page) . This makes any work past basic Library and Serial coding laborious.
Would be willing to make proper documentation. Given from comments elsewhere, "source is documentation", to which I respectfully disagree.
Arduino-development/libraries/MySensors/core/MyGatewayTransportMQTTClient.cpp Line #26 has the hint
// Topic structure: MY_MQTT_PUBLISH_TOPIC_PREFIX/NODE-ID/SENSOR-ID/CMD-TYPE/ACK-FLAG/SUB-TYPE
This is what it looks like:
Now when you proceed to inject packets into the MySensors network, you can send data to the appropriate topic or send data directly to the serial port.
The structure on MQTT that the data is stored is the following:
MySensors/nodeId/childSensorId/messageType/ack/subType
And the msg.payload is your dataNote that MySensors/ is user configurable within this MQTT-SerialGateway. I chose MySensors. You can change this by modifying "Formats MQTT topic" and "Convert Topic to Serial Protocol" and change "MySensors" to the name you want. Don't use spaces. MQTT doesn't always like that.
This does allow that you can have 2 or more gateways and have different topics for different networks to increase the number of your devices past 256.
I also have not included the messageType or subType substitutions found on the lists in Serial API. That would have included an extra step if that was stored in MQTT to translate between the messageType(number) and messageType(variable name). Although I may write a quick lookup depending on how bad I need that.
-
RE: Riots
In all honesty, I'm not anti-corporation or any of that. But I like my tech, new and old both.
If a company came out with an offering that had a cheap hub (for web interface locally), with a MQTT client to publish data to, I'd be all over it. I'd also like the ability to toggle on/off the "cloud" capability (read as 'Other peoples servers').
But eventually, these services eventually are shut down, upgrade to obsolescence of your hardware, go bankrupt, and oh so many other failure options. And truth be told, most Kickstarters fail. I know a few hardware devs at our local hackerspace that has a fistful of KS one off hardware that had cloud connectivity. Not any more.
Change of topic... slightly
What is the state of the art in IoT hardware that supports open protocols (MQTT/CoAP/AMQP)? Other than roll your own, are there open offerings?
-
RE: Riots
Am I the only one that actively denigrates IoT projects that demand data be sent to some remote server and then funneled back via a half-baked API? Why not MQTT/CoAP/AMQP ?
Or am I the only one that despises that companies can remotely update firmware at a whim, like the way that Phillips did deactivating all 3rd party lights? It took a day to "fix", but they retain the ability as they choose. https://www.reddit.com/r/Hue/comments/3wy5t7/philips_hue_debacle_the_online_press_is_picking/
Or that my profiling data on all of my devices are, by default, someone else's data? One can glean a lot of stuff from a sensor-covered house. This can be scary: https://www.researchgate.net/publication/224155275_Real-Time_Recognition_and_Profiling_of_Appliances_through_a_Single_Electricity_Sensor
Or that if the internet goes down, all my devices go dumb? Somehow
Device->DeviceGateway->Router->internet->Your Database Server->internet->router->DeviceGateway->Device
is better than....
Device->DeviceGateway->Controller->DeviceGateway->Device ??? Because that's what nRF24L01+ , Arduino Nano, Node-Red, and Mysensors lets me do.
But then again, there's a reason I'm the "Cranky Linux User"....
-
RE: repeater node with sensor
Looking at the code, there's no good reason to use that delay at all. You're already waiting for 600 seconds with the
if((millis() - oldTime) > 600000)
loop. The Delay is only recommended in the main codebase so that the sensor has time to regenerate the data. Some sensors have to wait for a bit or the measurement will be off, but we're talking about milliseconds here.
Just delete the whole line:
delay(dht.getMinimumSamplingPeriod());
and you should be perfectly fine. If you wanted to be on the safe side, you could do the following...
if((millis() - oldTime) > (600000 +dht.getMinimumSamplingPeriod() )
and that would include any delay that the sensor library might need.
All the best,
cranky -
RE: repeater node with sensor
You sure can. I made early on a MotionSensorRepeater using 1.5.0 . The gotcha is you need to implement some sort of NON_BLOCKING rate limiting so the sensor doesn't spam the repeater. If you use DELAY(), you will lose messages. A lot of them.
Also, I'm using a junky Sparkfun PIR sensor for this, with NO potentiometers for sensitivity or triggered duration, so I had to do duration in software. That's why the extra complication.
#define NODE_ID 3 #define CHILD_ID 5 // Id of the sensor child String ROOM_ID = " ID 5, living room repeater" ; #include <MySensor.h> #include <SPI.h> unsigned long MIN_TIME_TRIGGERED = 60000 ; // Time for sensor to report "off". Normally set on the PIR itself but this is junky sparkfun. boolean previousTripped = LOW; unsigned long PREVIOUS_TRIPPED_TIME = millis(); unsigned long MIN_RETRIGGER = 3500; #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!) #define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) MySensor gw; // Initialize motion message MyMessage msg(CHILD_ID, V_TRIPPED); void setup() { gw.begin(NULL, NODE_ID, true); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("Motion Sensor", "1.0"); pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input // Register all sensors to gw (they will be created as child devices) gw.present(CHILD_ID, S_MOTION); } void loop() { boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; // Sensor must be HIGH and not yet sent the status of the sensor if ((tripped == HIGH) && (tripped != previousTripped) ) { Serial.print(tripped); Serial.println(ROOM_ID); gw.send(msg.set(tripped ? "1" : "0")); // Send tripped value to gw previousTripped = tripped; PREVIOUS_TRIPPED_TIME = millis(); } // Is sensor HIGH, already sent to gateway, and under the minimum time to trigger? Then don't send if ( (PREVIOUS_TRIPPED_TIME + MIN_RETRIGGER) < millis() ) { if ( (tripped == HIGH) && (tripped == previousTripped) ) { Serial.println("Counter Reset"); PREVIOUS_TRIPPED_TIME = millis(); } } // Is sensor low and not sent? Then send LOW to gateway if (tripped == LOW) { if ( ((PREVIOUS_TRIPPED_TIME + MIN_TIME_TRIGGERED) <= millis() ) && (tripped != previousTripped) ) { Serial.print(tripped); Serial.println(ROOM_ID); gw.send(msg.set(tripped ? "1" : "0")); // Send tripped value to gw previousTripped = tripped; PREVIOUS_TRIPPED_TIME = millis(); } } gw.process(); // makes the node repeat }
-
RE: Neopixel Node, using 1.6.0 Beta
Oh, @msebbe @AWI , I have a FastLED version with a decent web API and web interface available here: http://forum.mysensors.org/topic/2705/fastled-neopixel-ws2811-node-from-arduino-code-to-web-page-with-api
It's working pretty damn well Still working on my front end interface, since I'm not a designer (well, I am a 3d cad designer, not web dev).
Oh, and if you knew my controller's name, you could communicate with it via TOR. Just like corporate solutions, I can communicate and control my gateway from anywhere in the world!
-
RE: MyController+Domoticz at same time?
You'll also probably want node-red-contrib-mysensors and a few other modules on flows.nodered.org
I use TOR extensively for being able to nicely manage and manipulate data on my network securely. The trick is a few things:
TOR: Providing a Hidden Service to SSH and HTTPS
Node-Red: Self-signed certs, HTTPS, and user authentication turned on.
Mosquitto: Providing MQTTSSL. node-red-contrib-mqttssl provides support for thatBut hek was gracious to make a "Controller>Node-Red" subforum, so come join me there!
Edit: also, because npm is sometimes really braindead sometimes, try using -debug with whatever you're doing. It will many a times make it work where without debut will just hang forever.
-
RE: FastLED / Neopixel (ws2811) Node, From Arduino code to Web page (with API)
FastLED Arduino sketch is done, along with appropriate Node-red subflow and website.
And it was surprisingly easy! FastLED is a cinch to work with
I'll probably call it ws2811 (Neopixel/FastLED) Node
Arduino code:
//#define MY_DEBUG #define MY_RADIO_NRF24 #define MY_NODE_ID 9 #include <SPI.h> #include <MySensor.h> #include "FastLED.h" FASTLED_USING_NAMESPACE #if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000) #warning "Requires FastLED 3.1 or later; check github for latest code." #endif #define DATA_PIN 3 //#define CLK_PIN 4 #define LED_TYPE WS2811 #define COLOR_ORDER GRB #define NUM_LEDS 38 CRGB leds[NUM_LEDS]; uint8_t gHue = 0; unsigned int currentSpeed = 0 ; int brightness = 96; unsigned int requestedMode = 0 ; int messageType = 0 ; int previousMessageType = -1; String hexColor = "000000" ; unsigned long previousTime = 0 ; void setup() { delay(1000); Serial.begin(115200); FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); FastLED.setBrightness(brightness); FastLED.show(); } void presentation() { sendSketchInfo("FastLED Node", "1.0"); present(0, S_RGB_LIGHT, "Makes strip said color", true); } void loop() { switch (messageType) { //************** CASE 1 ************** case (1): Serial.print("Hex color override: "); Serial.println(hexColor); colorWipe(); messageType = 0 ; break; //************** CASE 2 ************** case (2): if ( (previousTime + (long) currentSpeed ) < millis() ) { if (requestedMode == 2) {rainbow(); FastLED.show(); } if (requestedMode == 3) {rainbowWithGlitter();FastLED.show(); } if (requestedMode == 4) {addGlitter(80);FastLED.show(); } if (requestedMode == 5) {confetti();FastLED.show(); } if (requestedMode == 6) {sinelon();FastLED.show(); } if (requestedMode == 7) {bpm();FastLED.show(); } if (requestedMode == 8) {juggle();FastLED.show(); } previousTime = millis(); } break; //************** CASE 3 ************** case (3): // Adjust timing of case 2 using non-blocking code (no DELAYs) Serial.print("Case 3 received. Speed set to: "); Serial.print(currentSpeed); Serial.println(" ms."); messageType = 2; break; //************** CASE 4 ************** case (4): // Adjust brightness of whole strip of case 2 using non-blocking code (no DELAYs) Serial.print("Case 4 received. Brightness set to: "); Serial.println(brightness); FastLED.setBrightness(brightness); FastLED.show(); messageType = previousMessageType ; // We get off type 4 ASAP break; } } void receive(const MyMessage &message) { Serial.println("Message received: "); if (message.type == V_RGB) { messageType = 1 ; hexColor = message.getString(); Serial.print("RGB color: "); Serial.println(hexColor); } if (message.type == V_VAR1) { requestedMode = message.getInt(); Serial.println(requestedMode); messageType = 2 ; Serial.print("Neo mode: "); Serial.println(requestedMode); } if (message.type == V_VAR2) { // This line is for the speed of said mode currentSpeed = message.getInt() ; Serial.println(currentSpeed); messageType = 3 ; Serial.print("Neo speed: "); Serial.println(currentSpeed); } if (message.type == V_VAR3) { // This line is for the brightness of said mode brightness = message.getInt() ; //if(brightness > 255) {brightness = 255;} //if(brightness < 0) {brightness = 0;} Serial.println(brightness); previousMessageType = messageType; messageType = 4 ; Serial.print("Neo brightness: "); Serial.println(brightness); } } //********************** FastLED FUNCTIONS *********************** void colorWipe() { for (int i = 0; i < NUM_LEDS ; i++) { leds[i] = strtol( &hexColor[0], NULL, 16); FastLED.show(); } } void rainbow() { // FastLED's built-in rainbow generator fill_rainbow( leds, NUM_LEDS, gHue++, 7); } void rainbowWithGlitter() { // built-in FastLED rainbow, plus some random sparkly glitter fill_rainbow( leds, NUM_LEDS, gHue++, 7); FastLED.show(); addGlitter(80); } void addGlitter( fract8 chanceOfGlitter) { if ( random8() < chanceOfGlitter) { leds[ random16(NUM_LEDS) ] += CRGB::White; } } void confetti() { // random colored speckles that blink in and fade smoothly fadeToBlackBy( leds, NUM_LEDS, 10); int pos = random16(NUM_LEDS); leds[pos] += CHSV( gHue + random8(64), 200, 255); } void sinelon() { // a colored dot sweeping back and forth, with fading trails fadeToBlackBy( leds, NUM_LEDS, 20); int pos = beatsin16(13, 0, NUM_LEDS); leds[pos] += CHSV( gHue, 255, 192); } void bpm() { // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint8_t BeatsPerMinute = 62; CRGBPalette16 palette = PartyColors_p; uint8_t beat = beatsin8( BeatsPerMinute, 64, 255); for ( int i = 0; i < NUM_LEDS; i++) { //9948 leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10)); } } void juggle() { // eight colored dots, weaving in and out of sync with each other fadeToBlackBy( leds, NUM_LEDS, 20); byte dothue = 0; for ( int i = 0; i < 8; i++) { leds[beatsin16(i + 7, 0, NUM_LEDS)] |= CHSV(dothue, 200, 255); dothue += 32; } }
FastLED Node subflow:
[{"id":"5bb468f1.8ac468","type":"subflow","name":"Neopixel Node","info":"","in":[{"x":67,"y":225,"wires":[{"id":"b168409e.83cfa"}]}],"out":[{"x":731,"y":237,"wires":[{"id":"18fb6ecc.c732b9","port":0}]}]},{"id":"18fb6ecc.c732b9","type":"mysdecenc","z":"5bb468f1.8ac468","name":"","x":627,"y":237,"wires":[[]]},{"id":"d4cbf034.7f9f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Solid RGB set","nodeid":"9","childid":0,"subtype":"40","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":453,"y":175,"wires":[["18fb6ecc.c732b9"]]},{"id":"f841fa59.3ad42","type":"mysencap","z":"5bb468f1.8ac468","name":"Mode Call","nodeid":"9","childid":0,"subtype":"24","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":446,"y":211,"wires":[["18fb6ecc.c732b9"]]},{"id":"43e75cfc.4fd6f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Speed Call","nodeid":"9","childid":0,"subtype":"25","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":451,"y":248,"wires":[["18fb6ecc.c732b9"]]},{"id":"78baceb2.c1add","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":302,"y":174,"wires":[["d4cbf034.7f9f4"]]},{"id":"4aa5e51d.b8370c","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":305,"y":210,"wires":[["f841fa59.3ad42"]]},{"id":"fdfcef4c.e51f8","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":307,"y":247,"wires":[["43e75cfc.4fd6f4"]]},{"id":"b168409e.83cfa","type":"function","z":"5bb468f1.8ac468","name":"","func":"var hexcolor = msg.payload.hexcolor;\nvar mode = msg.payload.mode;\nvar speed = msg.payload.speed;\nvar brightness = msg.payload.brightness;\n\nif (hexcolor !== undefined ){ // Pass the hexcolor down the path\n msg.payload = hexcolor ;\n return [msg, null, null, null];\n}\n\nif (mode !== undefined ){ // Pass the pattern mode down the path\n msg.payload = mode ;\n return [null, msg, null, null];\n}\n\nif (speed !== undefined ){ // Pass the speed down the path\n msg.payload = speed ;\n return [null, null, msg, null];\n}\n\nif (brightness !== undefined ){ // Pass the speed down the path\n msg.payload = brightness ;\n return [null, null, null, msg];\n}","outputs":"4","noerr":0,"x":155,"y":225,"wires":[["78baceb2.c1add"],["4aa5e51d.b8370c"],["fdfcef4c.e51f8"],["9eae602d.d13d88"]]},{"id":"842664d8.6ea65","type":"mysencap","z":"5bb468f1.8ac468","name":"Brightness Call","nodeid":"9","childid":0,"subtype":"26","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":455,"y":288,"wires":[["18fb6ecc.c732b9"]]},{"id":"9eae602d.d13d88","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":305,"y":285,"wires":[["842664d8.6ea65"]]},{"id":"e2669ab0.c9db9","type":"subflow:5bb468f1.8ac468","z":"395349b4.bbb1be","name":"","x":529,"y":263,"wires":[["d34e424a.c3ba6"]]}]
FastLED Node Web API
[{"id":"57fddc52.c8549c","type":"serial-port","z":"395349b4.bbb1be","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"5bb468f1.8ac468","type":"subflow","name":"Neopixel Node","info":"","in":[{"x":67,"y":225,"wires":[{"id":"b168409e.83cfa"}]}],"out":[{"x":731,"y":237,"wires":[{"id":"18fb6ecc.c732b9","port":0}]}]},{"id":"18fb6ecc.c732b9","type":"mysdecenc","z":"5bb468f1.8ac468","name":"","x":627,"y":237,"wires":[[]]},{"id":"d4cbf034.7f9f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Solid RGB set","nodeid":"9","childid":0,"subtype":"40","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":453,"y":175,"wires":[["18fb6ecc.c732b9"]]},{"id":"f841fa59.3ad42","type":"mysencap","z":"5bb468f1.8ac468","name":"Mode Call","nodeid":"9","childid":0,"subtype":"24","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":446,"y":211,"wires":[["18fb6ecc.c732b9"]]},{"id":"43e75cfc.4fd6f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Speed Call","nodeid":"9","childid":0,"subtype":"25","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":451,"y":248,"wires":[["18fb6ecc.c732b9"]]},{"id":"78baceb2.c1add","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":302,"y":174,"wires":[["d4cbf034.7f9f4"]]},{"id":"4aa5e51d.b8370c","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":305,"y":210,"wires":[["f841fa59.3ad42"]]},{"id":"fdfcef4c.e51f8","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":307,"y":247,"wires":[["43e75cfc.4fd6f4"]]},{"id":"b168409e.83cfa","type":"function","z":"5bb468f1.8ac468","name":"","func":"var hexcolor = msg.payload.hexcolor;\nvar mode = msg.payload.mode;\nvar speed = msg.payload.speed;\nvar brightness = msg.payload.brightness;\n\nif (hexcolor !== undefined ){ // Pass the hexcolor down the path\n msg.payload = hexcolor ;\n return [msg, null, null, null];\n}\n\nif (mode !== undefined ){ // Pass the pattern mode down the path\n msg.payload = mode ;\n return [null, msg, null, null];\n}\n\nif (speed !== undefined ){ // Pass the speed down the path\n msg.payload = speed ;\n return [null, null, msg, null];\n}\n\nif (brightness !== undefined ){ // Pass the speed down the path\n msg.payload = brightness ;\n return [null, null, null, msg];\n}","outputs":"4","noerr":0,"x":155,"y":225,"wires":[["78baceb2.c1add"],["4aa5e51d.b8370c"],["fdfcef4c.e51f8"],["9eae602d.d13d88"]]},{"id":"842664d8.6ea65","type":"mysencap","z":"5bb468f1.8ac468","name":"Brightness Call","nodeid":"9","childid":0,"subtype":"26","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":455,"y":288,"wires":[["18fb6ecc.c732b9"]]},{"id":"9eae602d.d13d88","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":305,"y":285,"wires":[["842664d8.6ea65"]]},{"id":"944f576d.f793c8","type":"http in","z":"395349b4.bbb1be","name":"","url":"/neopixel","method":"get","swaggerDoc":"","x":84,"y":182,"wires":[["f7981706.1d0b08"]]},{"id":"512f4e11.a571b8","type":"template","z":"395349b4.bbb1be","name":"Prints data ","field":"payload","format":"handlebars","template":"Hexcolor: {{payload.hexcolor}} \nMode: {{payload.mode}} \nSpeed: {{payload.speed}}","x":528,"y":164,"wires":[["98fabd8f.db8f8"]]},{"id":"e2669ab0.c9db9","type":"subflow:5bb468f1.8ac468","z":"395349b4.bbb1be","name":"","x":529,"y":263,"wires":[["d34e424a.c3ba6"]]},{"id":"98fabd8f.db8f8","type":"http response","z":"395349b4.bbb1be","name":"","x":731,"y":164,"wires":[]},{"id":"2e9eb2d7.d49bfe","type":"debug","z":"395349b4.bbb1be","name":"","active":true,"console":"false","complete":"false","x":536,"y":73,"wires":[]},{"id":"5b91c6df.ea9e18","type":"http in","z":"395349b4.bbb1be","name":"","url":"/neopixel","method":"post","swaggerDoc":"","x":82,"y":145,"wires":[["f7981706.1d0b08"]]},{"id":"9c565a2d.52db08","type":"comment","z":"395349b4.bbb1be","name":"Valid commands ~readme~","info":"hexcolor:000000~ffffff\n First 2 are red, second 2 are green, last 2 are blue. \n Just like standard HTML hexcolors without #\nmode:2~4\n 2 is rainbow\n 3 is glitter rainbow rainbow\n 4 is glitter. kind of boring\n 5 is confetti\n 6 is Cylon tracers\n 7 is a Beats per minute. currently staticly set to 62bpm in code\n 8 is juggle\nspeed:0~9\n Number is milliseconds since last time.\n 0ms is little delay as possible\n 200ms is max for website but can go longer (why?)","x":124,"y":266,"wires":[]},{"id":"d34e424a.c3ba6","type":"serial out","z":"395349b4.bbb1be","name":"","serial":"57fddc52.c8549c","x":743,"y":263,"wires":[]},{"id":"f7981706.1d0b08","type":"function","z":"395349b4.bbb1be","name":"Combine Post/Get","func":"return msg;","outputs":1,"noerr":0,"x":298,"y":163,"wires":[["2e9eb2d7.d49bfe","512f4e11.a571b8","e2669ab0.c9db9"]]}]
FastLED Node Webpage
[{"id":"9d9299f7.ff826","type":"http in","z":"163c57ed.326588","name":"","url":"/index.html","method":"get","swaggerDoc":"","x":173,"y":84,"wires":[["8b6f494e.e388b8"]]},{"id":"8b6f494e.e388b8","type":"template","z":"163c57ed.326588","name":"index.html","field":"payload","format":"html","template":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"utf-8\" />\n\t<title>Neopixel MySensors Configuration</title>\n\t<script src=\"/jquery.min.js\"></script>\n\t\n\t<script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='rainbow']\").click(function(){ $.post(\"/neopixel\",{ mode: \"2\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='glitterrainbow']\").click(function(){ $.post(\"/neopixel\",{ mode: \"3\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='glitter']\").click(function(){ $.post(\"/neopixel\",{ mode: \"4\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='confetti']\").click(function(){ $.post(\"/neopixel\",{ mode: \"5\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='cylon']\").click(function(){ $.post(\"/neopixel\",{ mode: \"6\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='bpm']\").click(function(){ $.post(\"/neopixel\",{ mode: \"7\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='juggle']\").click(function(){ $.post(\"/neopixel\",{ mode: \"8\"}, function() {} ); });\n });\n </script>\n \n \n\n</head>\n<body>\n\n<div align=\"center\">\n<canvas width=\"850\" height=\"450\" id=\"canvas_picker\"></canvas>\n<div id=\"hex\">HEX: <input type=\"text\"></input></div>\n\n<button name=\"rainbow\">Rainbow</button>\n<button name=\"glitterrainbow\">Glitter Rainbow</button>\n<button name=\"glitter\">Glitter</button>\n<button name=\"confetti\">Confetti</button>\n<button name=\"cylon\">Cylon</button>\n<button name=\"bpm\">BPM</button>\n<button name=\"juggle\">Juggle</button>\n\n<br><br>\n0 ms. <input type=\"range\" min=\"0\" max=\"200\" onchange=\"emitSpeed(this.value)\"/> 200 ms.<br>\n0 <input type=\"range\" min=\"0\" max=\"255\" onchange=\"emitBrightness(this.value)\"/> 255\n</div>\n\n<script type=\"text/javascript\">\n\tvar canvas = document.getElementById('canvas_picker').getContext('2d');\n\n\t// create an image object and get itβs source\n\tvar img = new Image();\n\timg.src = '/colorwheel3.png';\n\n\t// copy the image to the canvas\n\t$(img).load(function(){ canvas.drawImage(img,0,0); });\n\n\t// http://www.javascripter.net/faq/rgbtohex.htm\n\tfunction rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B)}\n\tfunction toHex(n) {\n\t n = parseInt(n,10);\n\t if (isNaN(n)) return \"00\";\n\t n = Math.max(0,Math.min(n,255));\n\t return \"0123456789ABCDEF\".charAt((n-n%16)/16) + \"0123456789ABCDEF\".charAt(n%16);\n\t}\n\t$('#canvas_picker').click(function(event){\n\t // getting user coordinates\n\t var x = event.pageX - this.offsetLeft;\n\t var y = event.pageY - this.offsetTop;\n\t // getting image data and RGB values\n\t var img_data = canvas.getImageData(x, y, 1, 1).data;\n\t var R = img_data[0];\n\t var G = img_data[1];\n\t var B = img_data[2]; var rgb = R + ',' + G + ',' + B;\n\t // convert RGB to HEX\n\t var hex = rgbToHex(R,G,B);\n\t // making the color the value of the input\n\t $('#rgb input').val(rgb);\n\t $('#hex input').val(hex);\n\t $.post( \"/neopixel\", { hexcolor: hex } ); }\n\t );\n</script>\n\n<script type=\"text/javascript\">\nfunction emitSpeed(fast)\n { $.post(\"/neopixel\",{ speed: fast}, function() {} ); }\n</script>\n\n<script type=\"text/javascript\">\nfunction emitBrightness(bright)\n { $.post(\"/neopixel\",{ brightness: bright}, function() {} ); }\n</script>\n\n\n</body>\n</html>","x":373,"y":82,"wires":[["bf09f135.39cec8"]]},{"id":"fa066d3a.ea6ff8","type":"http in","z":"163c57ed.326588","name":"","url":"/colorwheel3.png","method":"get","swaggerDoc":"","x":153,"y":134,"wires":[["eafd1d33.cc13b8"]]},{"id":"eafd1d33.cc13b8","type":"file in","z":"163c57ed.326588","name":"","filename":"/home/josh/colorwheel3.png","format":"","x":388,"y":134,"wires":[["bf09f135.39cec8"]]},{"id":"bf09f135.39cec8","type":"http response","z":"163c57ed.326588","name":"","x":638,"y":103,"wires":[]},{"id":"5e929b72.ba9364","type":"http in","z":"163c57ed.326588","name":"","url":"/jquery.min.js","method":"get","swaggerDoc":"","x":175,"y":186,"wires":[["521c39b0.344748"]]},{"id":"521c39b0.344748","type":"file in","z":"163c57ed.326588","name":"","filename":"/home/josh/jquery.min.js","format":"","x":397,"y":184,"wires":[["bf09f135.39cec8"]]}]
-
RE: MySensors 1.6 availability?
Ah, so it was a regression! I made my Neopixel node with this bug in mind. I just grabbed the newest 1.6 a few hours ago, so I'll assume it's fixed.
Cool beans!
-
RE: FastLED / Neopixel (ws2811) Node, From Arduino code to Web page (with API)
I am looking at an Arduino code rewrite using FastLED. But for right now, this works and works well.
I think I might have found a bug in the 1.6.0 beta MySensors. I need to confirm it's not my coding, but because of that, expect Speed call to change internally. Ideally, the API will stay the same, or be added to.
I will replicate with my ServoActuator to see if it's my coding or the beta.
-
FastLED / Neopixel (ws2811) Node, From Arduino code to Web page (with API)
This is running Dev 1.6.0 , so beware. You will have to convert it to 1.5.0 if you aren't running crazy like me!
Edited: There was a bug in the code where it had an unroutable IP address along with a script hosted at Google. Fixed.
Arduino Neopixel Node code
//#define MY_DEBUG #define MY_RADIO_NRF24 #define MY_NODE_ID 9 #include <SPI.h> #include <MySensor.h> #include <Adafruit_NeoPixel.h> #include <avr/power.h> Adafruit_NeoPixel strip = Adafruit_NeoPixel(38, 3, NEO_GRB + NEO_KHZ800); unsigned int requestedMode = 0 ; unsigned int requestedSpeed = 0 ; unsigned int currentSpeed = 0 ; int messageType = 0 ; long hexColor = -1 ; unsigned long previousTime = 0 ; int j = 0 ; int q = 0 ; void setup() { Serial.begin(115200); strip.begin(); strip.show(); Serial.println("Neopixel Node device ready"); } void presentation() { sendSketchInfo("Neopixel Node", "1.0"); present(0, S_RGB_LIGHT, "Makes strip said color", true); } void loop() { switch (messageType) { case (1): Serial.print("Hex color override: "); Serial.println(hexColor); colorWipe(hexColor); messageType = 0 ; break; case (2): if ( (previousTime + (long) currentSpeed) < millis() ){ if (requestedMode == 2) { if (j > 256) { j = 0;} for(int i=0; i<strip.numPixels(); i++) {strip.setPixelColor(i, Wheel((i+j) & 255)) ; strip.show(); } j++; if ( (j%255) == 0 ) { Serial.println("Rainbow completed, continuing");} } if (requestedMode == 3) { if (j > 256) { j = 0;} for(int i=0; i<strip.numPixels(); i++) {strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); strip.show(); } j = j + 5; if ( (j%255) == 0 ) { Serial.println("Rainbow cycle completed, continuing");} } if (requestedMode == 4) { if (j > 10) { j = 0;} if (q > 3) { q = 0;} for (int j=0; j<10; j++) { for (q=0; q < 3; q++) { for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, hexColor ); } strip.show(); delay(50); for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, 0); } } } } previousTime = millis(); } break; case (3): // Adjust timing of case 2 using non-blocking code (no DELAYs) Serial.print("Case 3 received. Speed set to: "); Serial.print(requestedSpeed * 10); Serial.println(" ms."); currentSpeed = requestedSpeed * 10; messageType = 2 ; break; } } void receive(const MyMessage &message) { Serial.println("Message received: "); if (message.type == V_RGB) { messageType = 1 ; String hexstring = message.getString(); Serial.print("RGB color: "); Serial.println(hexstring); hexColor = strtol( &hexstring[0], NULL, 16); } if (message.type == V_VAR1) { String junkString = message.getString(); Serial.println(junkString); requestedMode = junkString.charAt(0) - 48; messageType = 2 ; Serial.print("Neo mode: "); Serial.println(requestedMode); } if (message.type == V_VAR2) { // This line is for the speed of said mode String junkString = message.getString(); Serial.println(junkString); requestedSpeed = junkString.charAt(0) - 48; messageType = 3 ; Serial.print("Neo speed: "); Serial.println(requestedSpeed); } } //************* Neopixel subroutines, with DELAYs removed. *************** void rainbowCycle() { Serial.println("Rainbow Cycle loop"); uint16_t i, j; for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel for (i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));} strip.show(); } } void colorWipe(long number) { long r = hexColor >> 16; long g = hexColor >> 8 & 0xFF; long b = hexColor & 0xFF; for (uint16_t i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, r,g,b); strip.show(); } } uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if (WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else if (WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } else { WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } }
Node-Red Neopixel Node subroutine
[{"id":"5bb468f1.8ac468","type":"subflow","name":"Neopixel Node","info":"","in":[{"x":27,"y":212,"wires":[{"id":"b168409e.83cfa"}]}],"out":[{"x":721,"y":215,"wires":[{"id":"18fb6ecc.c732b9","port":0}]}]},{"id":"18fb6ecc.c732b9","type":"mysdecenc","z":"5bb468f1.8ac468","name":"","x":608,"y":214,"wires":[[]]},{"id":"d4cbf034.7f9f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Solid RGB set","nodeid":"9","childid":0,"subtype":"40","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":453,"y":175,"wires":[["18fb6ecc.c732b9"]]},{"id":"f841fa59.3ad42","type":"mysencap","z":"5bb468f1.8ac468","name":"Mode Call","nodeid":"9","childid":0,"subtype":"24","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":446,"y":211,"wires":[["18fb6ecc.c732b9"]]},{"id":"43e75cfc.4fd6f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Speed Call","nodeid":"9","childid":0,"subtype":"25","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":451,"y":248,"wires":[["18fb6ecc.c732b9"]]},{"id":"78baceb2.c1add","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":315,"y":174,"wires":[["d4cbf034.7f9f4"]]},{"id":"4aa5e51d.b8370c","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":318,"y":210,"wires":[["f841fa59.3ad42"]]},{"id":"fdfcef4c.e51f8","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":247,"wires":[["43e75cfc.4fd6f4"]]},{"id":"b168409e.83cfa","type":"function","z":"5bb468f1.8ac468","name":"","func":"var hexcolor = msg.payload.hexcolor;\nvar mode = msg.payload.mode;\nvar speed = msg.payload.speed;\n\nif (hexcolor !== undefined ){ // Pass the hexcolor down the path\n msg.payload = hexcolor ;\n return [msg, null, null];\n}\n\nif (mode !== undefined ){ // Pass the pattern mode down the path\n msg.payload = mode ;\n return [null, msg, null];\n}\n\nif (speed !== undefined ){ // Pass the speed down the path\n msg.payload = speed ;\n return [null, null, msg];\n}","outputs":"3","noerr":0,"x":166,"y":211,"wires":[["78baceb2.c1add"],["4aa5e51d.b8370c"],["fdfcef4c.e51f8"]]},{"id":"e2669ab0.c9db9","type":"subflow:5bb468f1.8ac468","z":"395349b4.bbb1be","name":"","x":529,"y":263,"wires":[["d34e424a.c3ba6"]]}]
Node-Red Neopixel Web API
[{"id":"57fddc52.c8549c","type":"serial-port","z":"395349b4.bbb1be","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"5bb468f1.8ac468","type":"subflow","name":"Neopixel Node","info":"","in":[{"x":27,"y":212,"wires":[{"id":"b168409e.83cfa"}]}],"out":[{"x":721,"y":215,"wires":[{"id":"18fb6ecc.c732b9","port":0}]}]},{"id":"18fb6ecc.c732b9","type":"mysdecenc","z":"5bb468f1.8ac468","name":"","x":608,"y":214,"wires":[[]]},{"id":"d4cbf034.7f9f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Solid RGB set","nodeid":"9","childid":0,"subtype":"40","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":453,"y":175,"wires":[["18fb6ecc.c732b9"]]},{"id":"f841fa59.3ad42","type":"mysencap","z":"5bb468f1.8ac468","name":"Mode Call","nodeid":"9","childid":0,"subtype":"24","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":446,"y":211,"wires":[["18fb6ecc.c732b9"]]},{"id":"43e75cfc.4fd6f4","type":"mysencap","z":"5bb468f1.8ac468","name":"Speed Call","nodeid":"9","childid":0,"subtype":"25","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":451,"y":248,"wires":[["18fb6ecc.c732b9"]]},{"id":"78baceb2.c1add","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":315,"y":174,"wires":[["d4cbf034.7f9f4"]]},{"id":"4aa5e51d.b8370c","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":318,"y":210,"wires":[["f841fa59.3ad42"]]},{"id":"fdfcef4c.e51f8","type":"function","z":"5bb468f1.8ac468","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":320,"y":247,"wires":[["43e75cfc.4fd6f4"]]},{"id":"b168409e.83cfa","type":"function","z":"5bb468f1.8ac468","name":"","func":"var hexcolor = msg.payload.hexcolor;\nvar mode = msg.payload.mode;\nvar speed = msg.payload.speed;\n\nif (hexcolor !== undefined ){ // Pass the hexcolor down the path\n msg.payload = hexcolor ;\n return [msg, null, null];\n}\n\nif (mode !== undefined ){ // Pass the pattern mode down the path\n msg.payload = mode ;\n return [null, msg, null];\n}\n\nif (speed !== undefined ){ // Pass the speed down the path\n msg.payload = speed ;\n return [null, null, msg];\n}","outputs":"3","noerr":0,"x":166,"y":211,"wires":[["78baceb2.c1add"],["4aa5e51d.b8370c"],["fdfcef4c.e51f8"]]},{"id":"944f576d.f793c8","type":"http in","z":"395349b4.bbb1be","name":"","url":"/neopixel","method":"get","swaggerDoc":"","x":84,"y":182,"wires":[["f7981706.1d0b08"]]},{"id":"512f4e11.a571b8","type":"template","z":"395349b4.bbb1be","name":"Prints data ","field":"payload","format":"handlebars","template":"Hexcolor: {{payload.hexcolor}} \nMode: {{payload.mode}} \nSpeed: {{payload.speed}}","x":528,"y":164,"wires":[["98fabd8f.db8f8"]]},{"id":"e2669ab0.c9db9","type":"subflow:5bb468f1.8ac468","z":"395349b4.bbb1be","name":"","x":529,"y":263,"wires":[["d34e424a.c3ba6"]]},{"id":"98fabd8f.db8f8","type":"http response","z":"395349b4.bbb1be","name":"","x":731,"y":164,"wires":[]},{"id":"2e9eb2d7.d49bfe","type":"debug","z":"395349b4.bbb1be","name":"","active":true,"console":"false","complete":"false","x":536,"y":73,"wires":[]},{"id":"5b91c6df.ea9e18","type":"http in","z":"395349b4.bbb1be","name":"","url":"/neopixel","method":"post","swaggerDoc":"","x":82,"y":145,"wires":[["f7981706.1d0b08"]]},{"id":"9c565a2d.52db08","type":"comment","z":"395349b4.bbb1be","name":"Valid commands ~readme~","info":"hexcolor:000000~ffffff\n First 2 are red, second 2 are green, last 2 are blue. \n Just like standard HTML hexcolors without #\nmode:2~4\n 2 is slow rainbow\n 3 is fast rainbow\n 4 is theater chase. Must set a hexcolor before doing this\nspeed:0~9\n 0 is fastest, as 0 ms (0*10 ms) per loop\n 9 is slowest, as 90 ms (9*10 ms) per loop","x":124,"y":266,"wires":[]},{"id":"d34e424a.c3ba6","type":"serial out","z":"395349b4.bbb1be","name":"","serial":"57fddc52.c8549c","x":743,"y":263,"wires":[]},{"id":"f7981706.1d0b08","type":"function","z":"395349b4.bbb1be","name":"Combine Post/Get","func":"return msg;","outputs":1,"noerr":0,"x":298,"y":163,"wires":[["2e9eb2d7.d49bfe","512f4e11.a571b8","e2669ab0.c9db9"]]}]
Node-Red Neopixel Web interface
[{"id":"9d9299f7.ff826","type":"http in","z":"163c57ed.326588","name":"","url":"/index.html","method":"get","swaggerDoc":"","x":173,"y":84,"wires":[["8b6f494e.e388b8"]]},{"id":"8b6f494e.e388b8","type":"template","z":"163c57ed.326588","name":"index.html","field":"payload","format":"html","template":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n\t<meta charset=\"utf-8\" />\n\t<title>Neopixel MySensors Configuration</title>\n\t<script src=\"/jquery.min.js\"></script>\n\t\n\t<script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='rainbow']\").click(function(){ $.post(\"/neopixel\",{ mode: \"2\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='fastrainbow']\").click(function(){ $.post(\"/neopixel\",{ mode: \"3\"}, function() {} ); });\n });\n </script>\n \n <script type=\"text/javascript\">\n $(document).ready(function(){\n $(\"button[name='chase']\").click(function(){ $.post(\"/neopixel\",{ mode: \"4\"}, function() {} ); });\n });\n </script>\n \n \n\n</head>\n<body>\n\n<div align=\"center\">\n<canvas width=\"550\" height=\"450\" id=\"canvas_picker\"></canvas>\n<div id=\"hex\">HEX: <input type=\"text\"></input></div>\n\n<button name=\"rainbow\">Rainbow</button>\n<button name=\"fastrainbow\">Fast Rainbow</button>\n<button name=\"chase\">Chase</button><br><br>\n0 (fast) <input type=\"range\" min=\"0\" max=\"10\" onchange=\"emitValue(this.value)\"/> (slow) 10\n</div>\n\n<script type=\"text/javascript\">\n\tvar canvas = document.getElementById('canvas_picker').getContext('2d');\n\n\t// create an image object and get itβs source\n\tvar img = new Image();\n\timg.src = '/colorwheel3.png';\n\n\t// copy the image to the canvas\n\t$(img).load(function(){ canvas.drawImage(img,0,0); });\n\n\t// http://www.javascripter.net/faq/rgbtohex.htm\n\tfunction rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B)}\n\tfunction toHex(n) {\n\t n = parseInt(n,10);\n\t if (isNaN(n)) return \"00\";\n\t n = Math.max(0,Math.min(n,255));\n\t return \"0123456789ABCDEF\".charAt((n-n%16)/16) + \"0123456789ABCDEF\".charAt(n%16);\n\t}\n\t$('#canvas_picker').click(function(event){\n\t // getting user coordinates\n\t var x = event.pageX - this.offsetLeft;\n\t var y = event.pageY - this.offsetTop;\n\t // getting image data and RGB values\n\t var img_data = canvas.getImageData(x, y, 1, 1).data;\n\t var R = img_data[0];\n\t var G = img_data[1];\n\t var B = img_data[2]; var rgb = R + ',' + G + ',' + B;\n\t // convert RGB to HEX\n\t var hex = rgbToHex(R,G,B);\n\t // making the color the value of the input\n\t $('#rgb input').val(rgb);\n\t $('#hex input').val(hex);\n\t $.post( \"/neopixel\", { hexcolor: hex } ); }\n\t );\n</script>\n\n<script type=\"text/javascript\">\nfunction emitValue(newValue)\n { $.post(\"/neopixel\",{ speed: newValue}, function() {} ); }\n</script>\n\n\n</body>\n</html>","x":373,"y":82,"wires":[["bf09f135.39cec8"]]},{"id":"fa066d3a.ea6ff8","type":"http in","z":"163c57ed.326588","name":"","url":"/colorwheel3.png","method":"get","swaggerDoc":"","x":153,"y":134,"wires":[["eafd1d33.cc13b8"]]},{"id":"eafd1d33.cc13b8","type":"file in","z":"163c57ed.326588","name":"","filename":"/home/josh/colorwheel3.png","format":"","x":388,"y":134,"wires":[["bf09f135.39cec8"]]},{"id":"bf09f135.39cec8","type":"http response","z":"163c57ed.326588","name":"","x":638,"y":103,"wires":[]},{"id":"5e929b72.ba9364","type":"http in","z":"163c57ed.326588","name":"","url":"/jquery.min.js","method":"get","swaggerDoc":"","x":175,"y":186,"wires":[["521c39b0.344748"]]},{"id":"521c39b0.344748","type":"file in","z":"163c57ed.326588","name":"","filename":"/home/josh/jquery.min.js","format":"","x":397,"y":184,"wires":[["bf09f135.39cec8"]]}]
Location for the jquery.min.js : https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
Image for Color-Wheel:
Results:
-
RE: Node-Red as Controller
@hek As a meta-discussion, would you be so kind as to create a Node-Red Controller Subcategory?
Since Rasberry-Pi's recent addition to Raspbian including NR on all installs, I think we're going to see a lot more questions regarding the nRF and MySensors. And frankly, NR is just amazing
-
RE: Neopixel Node, using 1.6.0 Beta
You should be able to. I have this as Node ID 9, and Child ID 0.
9;0;1;1;40;(HEX) sets a consistent color of the appropriate HEX code.
9;0;1;1;24;(2 or 3 or 4) sets either slow rainbow, fast rainbow or theater chase
9;0;1;1;25;(0 through 9) sets speed. 0 is faster and 9 is slower.Node-Red is what I use, but this should work with any controller given those settings. Of course, use the standard MySensors serial protocol.
Tell me how you like it!
-
RE: Node-Red as Controller
The flow you are giving feedback on is from @FotoFieber , not I
I was a wee confused, as my flow didn't have a string conversion like that in there. Now, the Router->2d array IP addresses on nodered.org does, but I didn't link that.
Here's that link: http://flows.nodered.org/flow/9b48db38d8c2bee59367 . If you have a crappy ATT router, you can get a nice list of machines.
-
RE: debugging a network of MySensors nodes based on dev branch 1.6
Just from someone who's working pretty heavily in IoT...
I'd not recommend hooking up sensors to the gateway. Run the gateway as just a gateway. It will make things simpler in the long run.
Also, Arduino Nano clones are $1.80 from Aliexpress, and the short range nRF chips are $.63/each and the 1km range one is $3.
-
Neopixel Node, using 1.6.0 Beta
I've been working on a few different concepts about a new node type, called the "Neopixel Node"! Using 1.6.0 Beta MySensors.
Initially, I thought it would be easy to port the strandtest code over... I was wrong. The code is all blocking with delay() everywhere. It means that your sent messages to this node won't send. And then, what's the point?
So I am in the works to make the code as non-blocking as I can make it. So far, I have many functions non-blocking with the exception of the theatre crawling lights. And the delay at most is 150ms.
I pieced everything together on my controller side with Node-Red. I only wanted a basic shell of connecting functionality, whereas you can easily hook it up to a web gui with a few basic blocks.
And remember, the code is very rough right now. I'm working on making more functions non-blocking along with adding new patterns and cool ideas. But using Node-Red makes a very quick turn-around time for testing and updating! Perhaps we can get a Node-Red as a Controller forum added?
V_RGB = give this a hex code. 000000 is off, ff0000 is red
V_VAR1 = Different modes. 2 is slow rainbow. 3 is fast rainbow. 4 is theater chase after you use a hex code.
V_VAR2 = Speed control for mode 2 and 3 for V_VAR1[Node-Red Flow Code]
[{"id":"c02382bd.ae5","type":"serial-port","z":"387afd49.a6b0fa","serialport":"/dev/ttyUSB0","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":true},{"id":"23d05132.32938e","type":"serial out","z":"387afd49.a6b0fa","name":"","serial":"c02382bd.ae5","x":671,"y":298,"wires":[]},{"id":"db668f27.44ac8","type":"mysdecenc","z":"387afd49.a6b0fa","name":"","x":666,"y":217,"wires":[["23d05132.32938e"]]},{"id":"c18b87a6.cc82d8","type":"mysencap","z":"387afd49.a6b0fa","name":"Solid RGB set","nodeid":"9","childid":0,"subtype":"40","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":415,"y":110,"wires":[["db668f27.44ac8"]]},{"id":"3542cfac.f962d8","type":"mysencap","z":"387afd49.a6b0fa","name":"Mode Call","nodeid":"9","childid":0,"subtype":"24","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":414,"y":313,"wires":[["db668f27.44ac8"]]},{"id":"186b7cdb.c952e3","type":"mysencap","z":"387afd49.a6b0fa","name":"Speed Call","nodeid":"9","childid":0,"subtype":"25","internal":0,"ack":false,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":420,"y":470,"wires":[["db668f27.44ac8"]]},{"id":"29819ac0.48d326","type":"function","z":"387afd49.a6b0fa","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":277,"y":109,"wires":[["c18b87a6.cc82d8"]]},{"id":"8cfbe481.6b1de8","type":"function","z":"387afd49.a6b0fa","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":286,"y":312,"wires":[["3542cfac.f962d8"]]},{"id":"f40043ae.2a3dd8","type":"function","z":"387afd49.a6b0fa","name":"slash n","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":289,"y":469,"wires":[["186b7cdb.c952e3"]]},{"id":"f5a3d9a5.f04d5","type":"inject","z":"387afd49.a6b0fa","name":"Speed9 (slow)","topic":"","payload":"9","payloadType":"string","repeat":"","crontab":"","once":false,"x":115,"y":506,"wires":[["f40043ae.2a3dd8"]]},{"id":"346a22ac.72f7be","type":"inject","z":"387afd49.a6b0fa","name":"Speed0 (fast)","topic":"","payload":"0","payloadType":"string","repeat":"","crontab":"","once":false,"x":111,"y":431,"wires":[["f40043ae.2a3dd8"]]},{"id":"ccdef1a.ef36e1","type":"inject","z":"387afd49.a6b0fa","name":"rainbow","topic":"","payload":"2","payloadType":"string","repeat":"","crontab":"","once":false,"x":113,"y":267,"wires":[["8cfbe481.6b1de8"]]},{"id":"eeaad340.169418","type":"inject","z":"387afd49.a6b0fa","name":"fast rainbow","topic":"","payload":"3","payloadType":"string","repeat":"","crontab":"","once":false,"x":123,"y":303,"wires":[["8cfbe481.6b1de8"]]},{"id":"43c0b3c7.fd6814","type":"inject","z":"387afd49.a6b0fa","name":"","topic":"","payload":"000000","payloadType":"string","repeat":"","crontab":"","once":false,"x":88,"y":24,"wires":[["29819ac0.48d326"]]},{"id":"24524b50.eb8acc","type":"inject","z":"387afd49.a6b0fa","name":"","topic":"","payload":"ff0000","payloadType":"string","repeat":"","crontab":"","once":false,"x":87,"y":77,"wires":[["29819ac0.48d326"]]},{"id":"1b069543.32c0ab","type":"inject","z":"387afd49.a6b0fa","name":"","topic":"","payload":"00ff00","payloadType":"string","repeat":"","crontab":"","once":true,"x":87,"y":117,"wires":[["29819ac0.48d326"]]},{"id":"e789eab3.9a517","type":"inject","z":"387afd49.a6b0fa","name":"","topic":"","payload":"ffffff","payloadType":"string","repeat":"","crontab":"","once":false,"x":252,"y":23,"wires":[["29819ac0.48d326"]]},{"id":"d912e499.b4cc28","type":"inject","z":"387afd49.a6b0fa","name":"Speed5 (medium)","topic":"","payload":"5","payloadType":"string","repeat":"","crontab":"","once":false,"x":126,"y":471,"wires":[["f40043ae.2a3dd8"]]},{"id":"1087e912.c8ddbf","type":"inject","z":"387afd49.a6b0fa","name":"","topic":"","payload":"0000ff","payloadType":"string","repeat":"","crontab":"","once":false,"x":89,"y":154,"wires":[["29819ac0.48d326"]]},{"id":"2e6a0789.d500b","type":"inject","z":"387afd49.a6b0fa","name":"theater chase","topic":"","payload":"4","payloadType":"string","repeat":"","crontab":"","once":false,"x":128,"y":336,"wires":[["8cfbe481.6b1de8"]]},{"id":"f66f1235.3e7e58","type":"comment","z":"387afd49.a6b0fa","name":"Init solid color before using theater","info":"","x":153,"y":370,"wires":[]},{"id":"afeca932.c1ba68","type":"comment","z":"387afd49.a6b0fa","name":"Hex colors","info":"","x":92,"y":187,"wires":[]}]
[Arduino Sketch Code]
//#define MY_DEBUG #define MY_RADIO_NRF24 #define MY_NODE_ID 9 #include <SPI.h> #include <MySensor.h> #include <Adafruit_NeoPixel.h> #include <avr/power.h> Adafruit_NeoPixel strip = Adafruit_NeoPixel(38, 3, NEO_GRB + NEO_KHZ800); unsigned int requestedMode = 0 ; unsigned int requestedSpeed = 0 ; unsigned int currentSpeed = 0 ; int messageType = 0 ; long hexColor = -1 ; unsigned long previousTime = 0 ; int j = 0 ; int q = 0 ; void setup() { Serial.begin(115200); strip.begin(); strip.show(); Serial.println("Neopixel Node device ready"); } void presentation() { sendSketchInfo("Neopixel Node", "1.0"); present(0, S_RGB_LIGHT, "Makes strip said color", true); } void loop() { switch (messageType) { case (1): Serial.print("Hex color override: "); Serial.println(hexColor); colorWipe(hexColor); messageType = 0 ; break; case (2): if ( (previousTime + (long) currentSpeed) < millis() ){ if (requestedMode == 2) { if (j > 256) { j = 0;} for(int i=0; i<strip.numPixels(); i++) {strip.setPixelColor(i, Wheel((i+j) & 255)) ; strip.show(); } j++; if ( (j%255) == 0 ) { Serial.println("Rainbow completed, continuing");} } if (requestedMode == 3) { if (j > 256) { j = 0;} for(int i=0; i<strip.numPixels(); i++) {strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); strip.show(); } j = j + 5; if ( (j%255) == 0 ) { Serial.println("Rainbow cycle completed, continuing");} } if (requestedMode == 4) { if (j > 10) { j = 0;} if (q > 3) { q = 0;} for (int j=0; j<10; j++) { for (q=0; q < 3; q++) { for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, hexColor ); } strip.show(); delay(50); for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, 0); } } } } previousTime = millis(); } break; case (3): // Adjust timing of case 2 using non-blocking code (no DELAYs) Serial.print("Case 3 received. Speed set to: "); Serial.print(requestedSpeed * 10); Serial.println(" ms."); currentSpeed = requestedSpeed * 10; messageType = 2 ; break; } } void receive(const MyMessage &message) { Serial.println("Message received: "); if (message.type == V_RGB) { messageType = 1 ; String hexstring = message.getString(); Serial.print("RGB color: "); Serial.println(hexstring); hexColor = strtol( &hexstring[0], NULL, 16); } if (message.type == V_VAR1) { String junkString = message.getString(); Serial.println(junkString); requestedMode = junkString.charAt(0) - 48; messageType = 2 ; Serial.print("Neo mode: "); Serial.println(requestedMode); } if (message.type == V_VAR2) { // This line is for the speed of said mode String junkString = message.getString(); Serial.println(junkString); requestedSpeed = junkString.charAt(0) - 48; messageType = 3 ; Serial.print("Neo speed: "); Serial.println(requestedSpeed); } } //************* Neopixel subroutines, with DELAYs removed. *************** void rainbowCycle() { Serial.println("Rainbow Cycle loop"); uint16_t i, j; for (j = 0; j < 256 * 5; j++) { // 5 cycles of all colors on wheel for (i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));} strip.show(); } } void colorWipe(long number) { long r = hexColor >> 16; long g = hexColor >> 8 & 0xFF; long b = hexColor & 0xFF; for (uint16_t i = 0; i < strip.numPixels(); i++) { strip.setPixelColor(i, r,g,b); strip.show(); } } uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if (WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else if (WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } else { WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } }
-
RE: Node-Red as Controller
Ok. I think I finally got to the root of the issue. It's a mixture of "Inject" and mysdecenc errors. Inject mangles "\n" on the string inject node, and mysdecenc doesn't add the proper ending of the payload "\n" to complete the transmission from the gateway to the node.
I have a flow, and inside it is 2 duplicate paths of the same data. The upper one is a manual MySensors node-red node done with functions, and the lower is using the node-red-contri-mysensors nodes.
[{"id":"90402c72.682b08","type":"serial-port","z":"ec82138a.7e61d","serialport":"/dev/ttyUSB4","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"cbb9cba0.69cf1","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"500","payloadType":"string","repeat":"","crontab":"","once":false,"x":131,"y":274,"wires":[["7fb75e44.d87738"]]},{"id":"359a983d.9e87d8","type":"debug","z":"ec82138a.7e61d","name":"","active":true,"console":"false","complete":"true","x":800,"y":380,"wires":[]},{"id":"9a892a68.a4d97","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"1000","payloadType":"string","repeat":"","crontab":"","once":false,"x":131,"y":316,"wires":[["7fb75e44.d87738"]]},{"id":"473303a0.d810ec","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"0","payloadType":"string","repeat":"","crontab":"","once":false,"x":129,"y":233,"wires":[["7fb75e44.d87738"]]},{"id":"c84afb59.3425a8","type":"template","z":"ec82138a.7e61d","name":"convert to payload","field":"payload","format":"handlebars","template":"{{nodeId}};{{childSensorId}};{{subType}};{{messageType}};{{ack}};{{payload}}","x":544,"y":270,"wires":[["359a983d.9e87d8","6fc996d1.7babb"]]},{"id":"7fb75e44.d87738","type":"function","z":"ec82138a.7e61d","name":"Manual MySensors","func":"msg.nodeId = 10;\nmsg.childSensorId = 10;\nmsg.subType = 1;\nmsg.messageType = 1;\nmsg.ack = 3;\n\nmsg.payload = msg.payload + \"\\n\" ;\n\nreturn msg;","outputs":1,"noerr":0,"x":332,"y":270,"wires":[["c84afb59.3425a8"]]},{"id":"6fc996d1.7babb","type":"serial out","z":"ec82138a.7e61d","name":"","serial":"90402c72.682b08","x":818,"y":323,"wires":[]},{"id":"98c26eed.2fb63","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"500","payloadType":"string","repeat":"","crontab":"","once":false,"x":136,"y":431,"wires":[["952f68a.e0ff198"]]},{"id":"5d0a69be.2b841","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"1000","payloadType":"string","repeat":"","crontab":"","once":false,"x":136,"y":473,"wires":[["952f68a.e0ff198"]]},{"id":"f32d1e54.bde4b","type":"inject","z":"ec82138a.7e61d","name":"","topic":"","payload":"0","payloadType":"string","repeat":"","crontab":"","once":false,"x":134,"y":390,"wires":[["952f68a.e0ff198"]]},{"id":"d3587219.c775c8","type":"mysencap","z":"ec82138a.7e61d","name":"","nodeid":"10","childid":"10","subtype":"3","internal":0,"ack":true,"msgtype":"1","presentation":false,"presentationtype":0,"presentationtext":"","fullpresentation":false,"firmwarename":"","firmwareversion":"","x":478,"y":427,"wires":[["cf568bb2.74a438"]]},{"id":"cf568bb2.74a438","type":"mysdecenc","z":"ec82138a.7e61d","name":"","x":618,"y":427,"wires":[["6fc996d1.7babb","359a983d.9e87d8"]]},{"id":"952f68a.e0ff198","type":"function","z":"ec82138a.7e61d","name":"slash n on payload","func":"msg.payload = msg.payload + \"\\n\";\nreturn msg;","outputs":1,"noerr":0,"x":314,"y":427,"wires":[["d3587219.c775c8"]]}]
You will have to change the nodes to correspond to your actuators as well as your serial port. Aside that, with the appropriate fix, it works well.
/ Off to create my NeoPixel Node
-
RE: Node-Red as Controller
Hello! I've not had a chance to update my blog with new updates. I'm busy with converting over my site to a pure node-red backend and being able to push updates via NR on my laptop via clone-flow. But that aside....
There's currently a regression in the newest serial port node in NR.
Arduino Nano->SerialGateway->NR->MySensors works with receiving data. However
Data->MySensors encoder->Serial is currently not working. It's NOT MySensors' fault. If I open up console on Serial gateway and an actuator, I can manually send commands and show that radio does in fact work.Where I am at now, is trying to figure out where the node-red-node-serial is in error. I know the recent node.js has caused havoc in the node-red ecosystem, mainly with hardware-to-node modules.
But I'm glad people are referencing my work thus far
The CrankyLinuxUser (whois for email/phone) if you have any further questions.
-
Errors with Custom MySensors actuator (Neopixel/ws2812 Node)
Greetings,
I've been working with sensor networks with MySensors for quite some time. So far, it's one of the nicest APIs I've worked with in networking. But I wanted to build an actuator that would follow somewhat complicated commands to actuate a Neopixel strip.
I already have the code written, and from after reading all the documentation, should indeed work.
#include <Adafruit_NeoPixel.h> #include <avr/power.h> #include <MySensor.h> #include <SPI.h> Adafruit_NeoPixel strip = Adafruit_NeoPixel(38, 3, NEO_GRB + NEO_KHZ800); MySensor gw; void setup() { Serial.begin(115200); gw.begin(incomingMessage, 10, false); gw.sendSketchInfo("Neopixel Node", "1.0"); gw.present(0, S_CUSTOM); strip.begin(); strip.show(); Serial.println("Neopixel Node device ready"); } void loop() { gw.process(); } void incomingMessage(const MyMessage &message) { Serial.println("Incoming message"); if (message.type == V_STATUS){ // Turns on or off if (message.getInt() == 0){lightsOut(10);} } if (message.type == V_RGB){ // Makes it a solid color String hexstring = message.getString(); long number = (long) strtol( &hexstring[0], NULL, 16); colorWipe(number, 10); } if (message.type == V_VAR1){ //Where we put the modes switch( message.getInt() ){ case 1: Serial.println("Rainbow mode activated"); rainbow(20); break; case 2: Serial.println("Rainbow Cycle mode activated"); rainbowCycle(20); break; case 3: Serial.println("Theater chase lights mode activated"); theaterChaseRainbow(50); break; default: break; } } } void lightsOut(uint8_t wait) { for(uint16_t i=0; i<strip.numPixels(); i++) { strip.setPixelColor(i, 0); strip.show(); delay(wait); } } // Fill the dots one after the other with a color void colorWipe(uint32_t c, uint8_t wait) { for(uint16_t i=0; i<strip.numPixels(); i++) { strip.setPixelColor(i, c); strip.show(); delay(wait); } } void rainbow(uint8_t wait) { uint16_t i, j; for(j=0; j<256; j++) { for(i=0; i<strip.numPixels(); i++) { strip.setPixelColor(i, Wheel((i+j) & 255)); } strip.show(); delay(wait); } } // Slightly different, this makes the rainbow equally distributed throughout void rainbowCycle(uint8_t wait) { uint16_t i, j; for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel for(i=0; i< strip.numPixels(); i++) { strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255)); } strip.show(); delay(wait); } } //Theatre-style crawling lights. void theaterChase(uint32_t c, uint8_t wait) { for (int j=0; j<10; j++) { //do 10 cycles of chasing for (int q=0; q < 3; q++) { for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, c); //turn every third pixel on } strip.show(); delay(wait); for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, 0); //turn every third pixel off } } } } //Theatre-style crawling lights with rainbow effect void theaterChaseRainbow(uint8_t wait) { for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel for (int q=0; q < 3; q++) { for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on } strip.show(); delay(wait); for (int i=0; i < strip.numPixels(); i=i+3) { strip.setPixelColor(i+q, 0); //turn every third pixel off } } } } // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t Wheel(byte WheelPos) { WheelPos = 255 - WheelPos; if(WheelPos < 85) { return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); } else if(WheelPos < 170) { WheelPos -= 85; return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); } else { WheelPos -= 170; return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); } }
But when I compile, it works. Then I get the nice chirps from the gateway showing the devices are talking. I get no st:FAIL or anything. It's all OK in the debug.
As an example, from Node-red, I see the following when the Neopixel Node comes online
12/23/2015, 3:51:35 PM84cc7d74.87704msg : Object{ "payload": "1.5\n", "_msgid": "cdb13c1a.324ec", "rawData": [ "10", "255", "0", "0", "17", "1.5\n" ], "nodeId": 10, "childSensorId": 255, "messageType": 0, "ack": 0, "subType": 17 } 12/23/2015, 3:51:35 PM84cc7d74.87704msg : Object{ "payload": "0\n", "_msgid": "ff17a410.00e858", "rawData": [ "10", "255", "3", "0", "6", "0\n" ], "nodeId": 10, "childSensorId": 255, "messageType": 3, "ack": 0, "subType": 6 } 12/23/2015, 3:51:37 PM84cc7d74.87704msg : Object{ "payload": "Neopixel Node\n", "_msgid": "1e786c77.e18794", "rawData": [ "10", "255", "3", "0", "11", "Neopixel Node\n" ], "nodeId": 10, "childSensorId": 255, "messageType": 3, "ack": 0, "subType": 11 } 12/23/2015, 3:51:37 PM84cc7d74.87704msg : Object{ "payload": "1.0\n", "_msgid": "2dbec95b.d24136", "rawData": [ "10", "255", "3", "0", "12", "1.0\n" ], "nodeId": 10, "childSensorId": 255, "messageType": 3, "ack": 0, "subType": 12 } 12/23/2015, 3:51:37 PM84cc7d74.87704msg : Object{ "payload": "\n", "_msgid": "a4060382.5bfa", "rawData": [ "10", "0", "0", "0", "23", "\n" ], "nodeId": 10, "childSensorId": 0, "messageType": 0, "ack": 0, "subType": 23 }
-
Is this an improper use of S_CUSTOM? If so, can you guide me to the docs that indicate how to properly construct it?
-
Is it possible that my Node-red MYSENCAP node is improperly configured? My settings for it are
{"message-type": "set",
"Node ID" : "10" ,
"Child ID" : "0" ,
"Child Type" : "V_VAR1",
"ACK" : "off" ,
"Presentation" : "off"}
And then I proceed to send a "2" through an Inject node. That should send my Neopixel Node into a rainbowCycle() call.
- I would rather have each ws2312 on its own childID. That way, I could individually address them with "HEX color/childID" and program more emergent behavior. How would the pros at MySensors approach this?
Thank you,
Josh Conway -