Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Saturday, 15 October 2016

MQTT Part 4: Sniff meets Node-Red

So far we've used MQTT to publish sensor data from an Arduino, and subscribe to receive messages to display on a screen. Having written code to do each of those things, one of Sniff's strengths is that its pretty trivial to do both at the same time, just by running the script to do each at the same time. Here's the complete code to support both a screen and a sensor at the some time:

make i2c device 2
make display lcdi2c device 2
make displayFlush boolean

make spi device
make ethernet device D10
make networkMAC string "b6:ee:63:ed:95:cb"
make networkIP string ""
make networkConnected boolean
make networkPort number
make networkPeer string

make mqtt device
make clientid string
make message string
make topic string
make retain boolean

when start
.set clientid to networkMAC
.set networkPeer to "" #No DNS on Arduino!
.repeat until networkConnected
..tell mqtt to "connect"
.broadcast measureStuff
.set topic to "text"
.tell mqtt to "subscribe"
.set topic to "office/text"
.tell mqtt to "subscribe"
..tell mqtt to "loop"
..if not message = ""
...tell display to "show"

make thermometer dht11 device D2
make temperature number
make humidity number
when measureStuff
..tell thermometer to "read"
..set retain to yes
..set topic to "office/temperature"
..set message to [temperature]
..tell mqtt to "publish"
..set retain to yes
..set topic to "office/humidity"
..set message to [humidity]
..tell mqtt to "publish"
..wait 10 secs

You might notice that we're subscribed to both text and office/text. The intention here is that we might have several of these devices in different rooms - so we can publish a message to all of them at once, or to each individually.

With the physical/embedded side out of the way, we now need to think about what we want to do with that data we've collected. That means we probably have something running on a desktop machine. While we could easily write that in Sniff, we could also use Node Red.

Node Red is a javascript based system that is specifically designed for collecting messages, processing them and passing them on.  It works particularly well with MQTT, which is sort of to be expected given that they're developed by the same people.

Grab a copy of Node Red, and run through the first tutorial to get the basic idea...

time passes... OK - you're back! Great!

Now that you've got the general idea of Node Red make an MQTT input node, and tell it to subscribe to office/temperature on your server/broker. Connect the output to a debug node, and hit deploy.

When the Sniff code is running on the Arduino, you should see the temperature messages appearing in the debug window.

Next we can connect the MQTT input node to an MQTT output node which publishes the received temperature back to office/text, so that the measured temperature appears on the screen.

Now that we can fetch the data from the sensor, and push it back, we can add some processing the he middle. For example let's make the message a little friendlier. Just add a Function node between the two MQTT nodes.

We read the msg.payload, modify and and write it back before passing it on to the send node. In fact we can make any changes we like. For example we can indulge the British habit of reporting cold temperatures in C (it was -2 last night!), and warm temperatures in F (awesome holiday - 80 degrees all week!). There's little confusion as we simply never use the values between 20 and 50!

The next step is to handle temperature and humidity at the same time. Getting the data is easy, as we can just subscribe to office/+, but there's serious gotcha - this also matches office/text. This means when we publish the results, we'll trigger an input, which will trigger an output.... that would be bad. To get round that add a switch node, which only outputs its result if the msg.topic!="office/text".

We can just check the message topic to find out what kind of information we've received. Slightly less obvious is that when we receive an update to temperature, we'll need to combine it with the previously received humidity. Fortunalty this is pretty easy, as each node in the flow has a "context". Context is a variable that we can store values in, and they'll be there the next time the function is executed. When we receive a value we store it in the context, and then generate a new payload message from the stored values.

One final thing to deal with is the that our simple Sniff program only handles one line of text at a time, while out Javascript function bundles the Humidity and into a single packet. While there are lots of ways we could handle this, the easiest way is to have a split node, which separates the two lines into two separate messages. This produces our final flow:

And one the Arduino we see:

While its true, we could have coded all of this in Sniff on the Arduino, without any networking involved, and it would have been much simpler its worth remembering that these kinds of sensor/display devices might be deployed all round your house, school or factory. When a few hundred are boxed up, and bolted to the wall, and you need a ladder to even reach some of them, going out and reprogramming them because you want to make a minor change isn't really practical. It makes a lot of sense to keep those boxes as dumb as possible, while the "business logic" - the stuff you need to change, and develop is all in one place where you can get to it.

In addition by pushing the data out to Node Red we get an easy connection to all sorts of other data streams, like email, twitter, and websites.

No comments:

Post a Comment