MicroPython Air Boat

My daughter’s and I have built a number of air boat projects, but this time I thought that I’d try it using MicroPython. MicroPython is a lean and efficient implementation of the Python 3 programming language that includes a small subset of the Python standard library and is optimised to run on microcontrollers.

For this project my goal was to create a MicroPython application that was a standalone WiFi access point, and its used a small web server for controlling the air boat fans.

Hardware

The hardware that I used on this project included:

• 1 – ESP8266 module ($5-$10)
• 2 – L9110 Fans ($5 each)
• 1 – Uno proto shield (optional) or use a small breadboard
• 9V battery or portable phone charger
• K-Nex blocks
• small plastic box
• 2 – plastic water bottles
• duct tape

MicroPython is supported on a number of Wifi enabled ESP32 and ESP8266 modules. These modules are well priced with the NodeMCU modules starting around $5. It’s important to note that most of the ESP-8266 modules also support Lua and Arduino C/C++ programming.

nodemcu

For this project I used an Wemos ESP-8266 module, that comes in a Arduino Uno form factor. I like the Wemos modules because I can used my Uno proto shields and these modules supports 5V DC, as opposed to the typical MicroPython modules that only support 3.3V. The fans will work with 3.3V but they generate a lot more wind power at 5V.

The L9110 fans are designed for Arduino projects and they only cost about $5. These fans have four pins: VCC, GND, INA (direction), and INB (on/off). For this project I only used forward spinning fans, so only pin INB was used.

L9110_fan

Boat Construction

For the boat frame I used K’Nex pieces because they are light weight and sturdy, however there a lot of other materials that could be used. Water bottles were used for flotation, and duct tape was used to secure the bottles to the frame. To help protect the electronics a small plastic snack container was used. I wire wrapped the fans to the boat frame.

airboat

MicroPython Setup

There are a few choices for MicroPython development. I found that the uPyCraft IDE offered a nice integrated environment (Figure 5), and there are some excellent tutorials to help you get started.

upycraft

For MicroPython projects you typically create 2 Python applications, a boot.py and a main.py file. I like to equate this to Arduino where you have a setup() function and a loop() function. For this example I wanted to keep the documentation simple so I put everything in the boot.py file, but it’s recommended to use main.py for larger projects.

Creating an Access Point

The picture below shows how to setup an access point in just a few lines of code. For this example the access point is called ‘ESP32’ with a password of ‘12345678’. When the code is run you will be able to see when a remote user connects and disconnects to the access point.

access_point

MicroPython Web Server

After getting the Access Point working the next step is to create a Web server. This is a simple Web server project so I embedded the HTML content into my Python code, however for a more complex application I would definitely have my web pages as files that are independent from the code.

For the Web Server example application , we start with the access point connection code, then we setup a socket on port 80. The HTTP request/response sequence is passed through a function called web_page(request). In web_page(request) the code looks for keywords in the HREF request.

# MicroPython boot.py - Access Point Web Server

try:
  import usocket as socket
except:
  import socket

import network

station = network.WLAN(network.AP_IF)
station.active(True)
station.config(essid='ESP32')
station.config(authmode=3,password='12345678')

while station.isconnected() == False:
  pass

print('Connection successful')
print(station.ifconfig())

def web_page(request):
  
  fans_state = ""
  if request.find('/?forward') > 0:
    fans_state="Going Forward"
  if request.find('/?Stopped') > 0:
    fans_state="Stopped" 
  
  html = """<html><head> <title>Ice Boat Web Server</title> 
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,"> <style>
  html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
  h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}
  .button{display: inline-block; background-color: #e7bd3b; border: none; 
  border-radius: 4px; color: white; text-decoration: none; font-size: 30px; width:100%}
  </style></head>
  <body> <h1>Ice Boat Web Server</h1> 
  <p>ICE Boat : <strong>""" + fans_state + """</strong></p>
  <p><a href='/?forward'><button class="button">Forward</button></a></p>
  <p><a href='/?stop'><button class="button button">STOP</button></a></p>
  
  </body></html>"""
  
  return html

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

while True:
  conn, addr = s.accept()
  print('Got a connection from %s' % str(addr))
  request = conn.recv(1024)
  request = str(request)
  print('The Content = %s' % request)
  response = web_page(request)
  conn.send(response)
  conn.close()

The embedded HTML code passes keywords using anchor tags, for example: <a href=’/?forward’>. Often we use mobile frameworks like Bootstrap to help with formatting, however because we’re running a standalone access point we need to manually define all our style codes.

To access our MicroPython web server, use the address: 192.168.4.1. This is the default address (in the access point setup you can change this). When our web server is running we should be able to toggle the stop/forward states.

screen2

Writing Outputs

The MicroPython command line interface is good way to test outputs. To access the command line interface, use the connect button and then enter “Control-C”.

To manage pins on the hardware, machine library is used :

from machine import Pin

Then pin objects can be defined as either inputs or outputs:

Pin14 = Pin(14, Pin.IN)
Pin5 = Pin(5, Pin.OUT)

The value of a pin is read using: pinobject.value(), and set with: pinobject.value(thevalue) .

motor_test

Final Application

Now that we have all the pieces working independently we can pull it all together. For the final code I’ve defined two fans (motorR and motorL), and a fan control function is called from the web requests.

# MicroPython boot.py - Access Point and Airboat Web Controls
import time
try:
  import usocket as socket
except:
  import socket

from machine import Pin
import network

# Define the left, right and back fans pin
motorR = Pin(12,Pin.OUT)
motorL = Pin(4,Pin.OUT)

# start with fans stopped, Note: my FANs are 0=run
motorR.value(1)
motorL.value(1)


station = network.WLAN(network.AP_IF)
station.active(True)
station.config(essid='ESP32')
station.config(authmode=3,password='12345678')

while station.isconnected() == False:
  pass

print('Connection successful')
print(station.ifconfig())

def fancontrol(left,right):
  motorL.value(left)
  motorR.value(right)

def web_page(request):
  
  fans_state = "Stopped"
  if request.find('/?forward') > 0:
    fans_state="Going Forward"
    fancontrol(0,0)
  if request.find('/?left') > 0:
    fans_state="Going Left"
    fancontrol(1,0)
  if request.find('/?right') > 0:
    fans_state="Going Right" 
    fancontrol(0,1)
  if request.find('/?stop') > 0:
    fans_state="Stopped"
    fancontrol(1,1)
  
  html = """<html><head> <title>Air Boat Web Server</title> 
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,"> <style>
  html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
  h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}
  .button{display: inline-block; background-color: #e7bd3b; border: none; 
  border-radius: 4px; color: white; text-decoration: none; font-size: 30px; width:100%}
  .button2{background-color: #4286f4; width:49%}
  </style></head>
  <body> <h1>Air Boat Web Server</h1> 
  <p>Air Boat : <strong>""" + fans_state + """</strong></p>
  <p><a href='/?forward'><button class="button">Forward</button></a></p>
  <p><a href='/?left'><button class="button button2">LEFT</button></a>
  <a href='/?right'><button class="button button2" >RIGHT</button></a></p>
  <p><a href='/?stop'><button class="button button">STOP</button></a></p>
  
  </body></html>"""
  
  return html

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

while True:
  conn, addr = s.accept()
  print('Got a connection from %s' % str(addr))
  request = conn.recv(1024)
  request = str(request)
  print('The Content = %s' % request)
  response = web_page(request)
  conn.send(response)
  conn.close()

airboat_moving

Summary

You’ll be quite surprised about how fast even 2 fans will move the air boat. Balancing the direction of the fans or adding a simple rudder may be required to ensure that it keeps a straight forward direction.

I’ve done the same project on the exact same hardware in Anduino C++ and I would say the response speed is similar but the Python code might be slightly leaner. I found that the MicroPython IDE wasn’t as robust as the Arduino IDE, but I really enjoyed doing interactive Python testing from a command prompt.

I won’t be giving up on Arduino C++, but I can definitely see a place for MicroPython, especially for projects with lots of string manipulation.

 

MQTT and Javascript

MQTT (Message Queuing Telemetry Transport) is a  publish-subscribe-based messaging protocol that is used on many Internet of Things (IoT) projects. It works on top of the TCP/IP protocol and it is designed for connections with remote locations where a “small code footprint” is required or the network bandwidth is limited. The publish-subscribe messaging pattern requires a message broker.

MQTT_js_overview

There is support for MQTT on a large variety of programming languages and platforms. An Arduino or Raspberry Pi module can sent (or publish) I/O to a MQTT broker, and they can also receive (or subscribe) to data.

There are a number of MQTT brokers that can be used. One of the most popular ones is the Mosquitto MQTT broker, and it can be loaded on Windows, OSX and Linux systems. For this blog we will be using the Mosquitto test MQTT server. This Internet based server should not be used for real systems, but it is excellent for small short terms tests.

MQTT Web Sockets

The MQTT server has configurable MQTT and Web Socket ports. For a typical Raspberry Pi or Arduino connection, the default MQTT port 1883 would be used. In many Internet applications only certain ports are open, so for this reason a different MQTT Web Socket is used. This is configurable but ports like 80 or 8080 are typically used.MQTT_web_layout

Javascript Application

There are a number of MQTT javascript libraries that are available. One of the more popular ones is the Paho library that is available at:

https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js

As a first example we will look at creating 2 pages. The first page will  publish a value, and the second page will subscribe to the data.

MQTT_js_pubsub

The publish code is:

<html>
<head>
<title> MQTT Publish Message</title>
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>

<script>
// Define some MQTT variables
var mqtt_server = "";
var mqtt_port = "";
var mqtt_destname = "";

function send_mqtt_msg() {
// Send an MQTT message
  mqtt_server = document.getElementById("mqtt_server").value;
  mqtt_port = Number(document.getElementById("mqtt_port").value);
 

  client = new Paho.MQTT.Client(mqtt_server, mqtt_port,"");
  client.connect({onSuccess:onConnect});
  document.getElementById("pubmsg").innerHTML = "Trying to connect...
";
}
function onConnect() {
  document.getElementById("pubmsg").innerHTML = "New connection made...
";
  var mqtt_destname = document.getElementById("mqtt_destname").value;
  var mqtt_msg = document.getElementById("mqtt_msg").value;   
  message = new Paho.MQTT.Message(mqtt_msg);
  message.destinationName = mqtt_destname;
  client.send(message);
  document.getElementById("pubmsg").innerHTML = "topic:" + mqtt_destname + " = " + mqtt_msg + " ...sent";
}  
// called when a message arrives
</script>
<body>
<h1>MQTT Publish Test Page</h1>

Server Name: <input type="text" id="mqtt_server" value="test.mosquitto.org"><br><br>
Websocket: <input type="text" id="mqtt_port" value="8080"><br><br>
DestinationName: <input type="text" id="mqtt_destname" value="my_IoT_value1"><br><br>
Message: <input type="text" id="mqtt_msg" value="test message"><br><br>

<button onclick="send_mqtt_msg()">Publish MQTT Message</button>
</body>
<hr>
<div id=pubmsg></div>
</html>

The subscribe code is:

<html>
<head>
<title> MQTT Subscribe Message</title>
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script>

function sub_mqtt_msg() {
// Send an MQTT message
  var mqtt_server = document.getElementById("mqtt_server").value;
  var mqtt_port = Number(document.getElementById("mqtt_port").value);

  client = new Paho.MQTT.Client(mqtt_server, mqtt_port,"");
  client.onMessageArrived = onMessageArrived;
  client.onMessageArrived = onMessageArrived;
  client.connect({onSuccess:onConnect});
  document.getElementById("submsg").innerHTML = "Trying to connect...
";

}
function onConnect() {
  document.getElementById("submsg").innerHTML = "New connection made...
";
  var mqtt_destname = document.getElementById("mqtt_destname").value;  
  client.subscribe(mqtt_destname);
  document.getElementById("submsg").innerHTML = "Subscribing to topic: " + mqtt_destname + " ...
";
}
function onMessageArrived(message) {
  var result = message.destinationName + " : " + message.payloadString + "
";
  document.getElementById("submsg").innerHTML = result;
}

</script>
<body>
<h1>MQTT Subscribe Test Page</h1>

Server Name: <input type="text" id="mqtt_server" value="test.mosquitto.org"><br><br>
Websocket: <input type="text" id="mqtt_port" value="8080"><br><br>
DestinationName: <input type="text" id="mqtt_destname" value="my_IoT_value1"><br><br>

<button onclick="sub_mqtt_msg()">Subscript to MQTT</button>
<hr>
<h2>Subscribed Messages:</h2>
<div id=submsg></div>
</body>

</html>

Once you’ve got the basics down it’s possible to make some more advanced web interface pages.

Chart and Gauges

For your IoT projects there are a lot of Dash board options that are available. One of my favorites is Node-Red because it is totally free and standalone.

If you would like to create your own web interface there are a number of good javascript charting and gauge libraries available. For my examples I used Google charts with the Gauge chart . To simulate the inputs I used three of our MQTT Publish pages.

MQTT_js_sim

The code for the gauges page is :

<html>
<head>
<title>IoT - MQTT to JS</title>
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script src="https://www.gstatic.com/charts/loader.js" type="text/javascript"></script>

<script>
// MQTT variables
var MQTTnames = ["my_IoT_value1","my_IoT_value2","my_IoT_value3"];
var MQTTvalues = [0,0,0];


// Define the Google gauge chart
      google.charts.load('current', {'packages':['gauge']});
      google.charts.setOnLoadCallback(drawChart);

      function drawChart() {

        var data = google.visualization.arrayToDataTable([
          ['Label', 'Value'], 
      [MQTTnames[0], MQTTvalues[0]],
      [MQTTnames[1], MQTTvalues[1]],
      [MQTTnames[2], MQTTvalues[2]],      
        ]);

        var options = {
          width: 800, height: 1000,
          redFrom: 90, redTo: 100,
          yellowFrom:75, yellowTo: 90,
          minorTicks: 5
        };

        var chart = new google.visualization.Gauge(document.getElementById('chart_div'));

        chart.draw(data, options);

        setInterval(function() {
      for (var i=0; i < MQTTnames.length; i++) {
      data.setValue(i, 1, MQTTvalues[i]);
      }
          chart.draw(data, options);

      }, 1000);
}

// Create a client instance
client = new Paho.MQTT.Client("test.mosquitto.org", 8080,"");
client.onMessageArrived = onMessageArrived;

// connect the client
client.connect({onSuccess:onConnect});

// called when the client connects
function onMessageArrived(message) {
  
  for (var i=0; i < MQTTnames.length; i++) {
  if (message.destinationName == MQTTnames[i]) {
    MQTTvalues[i] = Number(message.payloadString);
  }
  }
}
function onConnect() {
  // Once a connection has been made, make a subscription and send a message.
  for (var i=0; i < MQTTnames.length; i++) {
  client.subscribe(MQTTnames[i]);
  }
}
// called when a message arrives
</script>
<body>
<h1  style = 'font-size: xx-large'>IoT - MQTT to JavaScript</h1>
<div id="chart_div" style="width: 100%; height: 100%;"></div>
</body>
</html>

There are many other charting options that could be used. Below is an example using the Google Chart library with bars instead of gauges.

MQTT_js_bars.png

Final Comment

Using Javascript to interact with your IoT projects open up a lot of potential for adding functionality. I found that the Python version of the Paho MQTT library to have better documentation and perhaps some more functions, but at the end of the day I was able to do all the I wanted.

Arduino talking MQTT to Node-Red

There are some great Arduino modules with integrated ESP-8266 wireless chips, some of the more popular modules are:

  • Adafruit HUZZAH
  • NodeMCU
  • WeMos

These modules allow you to do some interesting IoT (Internet of Things) projects. To connect the Arduino modules to PCs, Raspberry Pi’s or Linux nodes that are a number of communication choices. MQTT (Message Queue Telemetry Transport) is becoming one of the standards for this and it is pre-installed with Node-Red.

Plant Moisture Monitoring MQTT Example

Ard_mqtt_overview2

For our example we wanted to do a simple plant moisture example that used a solar charger and an Arduino Wemos module. We then setup an MQTT server on our Node-Red Raspberry Pi with a web dashboard.

Our goal was to get the MQTT technologies working, with some moisture inputs (and not a final plant monitoring system).

Moisture Sensors

Moisture sensors are very low cost and they start at about $2. The basic moisture sensor has 3 inputs; VCC, GND, and AO. Some sensors also include a digital output with a potentiometer to adjust the digital 0-1 moisture limit.

Our Arduino plant moisture setup is good for testing but not a good long term solution. When voltage is applied long term to moisture sensors ionization in the soil will cause a combination of false reading and deterioration of the sensor plates. We plan to do a future project where we will use relays to turn the sensors on/off and we will include solenoid values in a watering system.

MQTT on Arduino

There are a number of excellent MQTT libraries for Arduino, for this example we used the PubSubClient library. This library can be installed from the Arduino IDE by selecting the menu items:

Sketch -> Add Library -> Manage Libraries

To get MQTT setup you’ll need to:

  • define the SSID and password for your WAN
  • define the IP address for the MQTT server (the Node Red/Raspberry Pi node)
  • define some topic for the data

The nice thing about MQTT is that you can define topics for each of your data points. For this example we define the topic humidity to show the moisture sensor value, and msgtext to show the message (‘Needs Water’ or ‘).

Below is our sample Arduino code for passing the moisture data to our MQTT server.

/*
 Basic ESP8266 MQTT publish client example for a moisture sensor
*/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.
const char* ssid = "YOUR_SSID_NAME";
const char* password = "YOUR_PASSWORD";
const char* mqtt_server = "YOUR_NODE_RED_IP";

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {
  // Connecting to a WiFi network
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  // Loop until we're reconnected
  Serial.println("In reconnect...");
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("Arduino_Moisture")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(9600);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
}

void loop() {
  char msg[10];
  char msgtext[25];
  String themsg;
  if (!client.connected()) {
    reconnect();
  }
  
  int soil_moisture=analogRead(A0);  // read from analog pin A0
  Serial.print("analog value: ");
  Serial.println(soil_moisture);
  
  if((soil_moisture>300)&&(soil_moisture<700)) {
    Serial.println("Humid soil");
    sprintf(msgtext,"Humid soil",soil_moisture);
  } 
  else if ((soil_moisture>700)&&(soil_moisture<950)){
    Serial.println("Moist Soil");
    sprintf(msgtext,"Moist Soil",soil_moisture);
  }
  else if (soil_moisture <300) ){
    Serial.println("Needs water");    
    sprintf(msgtext,"Needs water",soil_moisture);
  }
  else
  {
      sprintf(msgtext,"Sensor Problem",soil_moisture);
  }

  sprintf(msg,"%i",soil_moisture);
  client.publish("humidity", msg);
  client.publish("soil", msgtext);
  delay(5000);
}

Node-Red

Node-Red is an excellent visual programming environment that is part of the Raspberry Pi base install. Node-Red is a simple tool to create your own Internet of Things applications. The base Node-Red installation includes MQTT interfacing components but it does not include an MQTT server.

If you don’t have a Raspberry Pi you can install Node-Red on Window, Mac OS or Linux systems. I’ve had good results running Node-Red on a very old low end laptop running Xubuntu, (see steps 1-3 in this linked guide).

MQTT Server on Node-Red

There are a number of free internet MQTT servers (iot.eclipse.org) that can be used or an MQTT server can be loaded directly on a local server (i.e. Mosquito).

Mosca is a standalone MQTT server that can be installed directly into Node-Red. The Mosca Node-Red component can be either installed at the command line by:

cd $HOME/.node-red

npm install node-red-contrib-mqtt-broker

Or the component can be install within the Node-Red web interface by selecting the “manage palette” option, and then search for mosca.

mosca_install

After Mosca is installed, all that is required is that a “mosca” node needs to be dragged and dropped into the Node-Red project.

mosca_mqtt_nodes

To connect the Arduino module to Node-Red mqtt inputs are added to the project.  The Arduino topics are defined in Node-Red by double-clicking on the mqtt node and then define the topic to match the Arduino topic.

mqtt_topic

After the MQTT connections are configured Web dashboards can present the final data. The Web dashboards offer a number of different components that could be used for this example I used a gauge and a text node.

To compile and view the Node-Red application, click on the Deploy button on the right side of the menu bar. To access the web dashboard enter: http://your-ip:1880/ui . Below is a example of what you should see.

NodeRed_MQTT_GUI

Final Thoughts

The Mosca MQTT server component allows for a simple standalone architecture to connect wireless Arduino modules into a Node-Red IoT solution.

We can also load Node-Red on Raspberry Pi data collection nodes, and have them publish data to a central Node-Red server.

 

 

 

Arduino talking TCP to Node-Red and Python

There are some great Arduino modules with integrated ESP-8266 wireless chips, some of the most popular of these modules are:

  • Adafruit HUZZAH
  • NodeMCU
  • WeMos

Along with these modules comes some excellent libraries.

For Arduino to PC or Raspberry Pi communications that are a few options to choose from. A TCP client/server is simple and straightforward and it is excellent for sending single point information. For sending multiple data points take a look at MQTT (Message Queuing Telemetry Transport), it’s a common standard for IoT applications and it’s built into Node-Red.

Arduino TCP Client

The Arduino module can be a simple TCP client that can talk to either a Python or a Node-Red TCP server. Below is an example that sends a random integer to a TCP server every 5 seconds.

/*
Test TCP client to send a random number
 */
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

ESP8266WiFiMulti WiFiMulti;

void setup() {
    Serial.begin(9600);

    // We start by connecting to a WiFi network
    const char * ssid = "your_ssid";       // your WLAN ssid
    const char * password = "your_password"; // your WLAN password
    WiFiMulti.addAP(ssid, password);

    Serial.println();
    Serial.print("Wait for WiFi... ");

    while(WiFiMulti.run() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
    }
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    delay(500);
}

void loop() {
    const uint16_t port = 8888;          // port to use
    const char * host = "192.168.0.123"; // address of server
    String msg;

    // Use WiFiClient class to create TCP connections
    WiFiClient client;

    if (!client.connect(host, port)) {
        Serial.println("connection failed");
        Serial.println("wait 5 sec...");
        delay(5000);
        return;
    }
   
    // Send a random number to the TCP server
    msg = String(random(0,100));
    client.print(msg);
    Serial.print("Sent : ");
    Serial.println(msg);
    client.stop();    
    delay(5000);
}

Node-Red TCP Server

Node-Red is an excellent visual programming environment that is part of the Raspberry Pi base install. Node-Red is a simple tool to create your own Internet of Things applications. The base Node-Red installation includes a TCP server and client.

To install the web dashboards enter:

sudo apt-get install npm
cd ~/.node-red
npm i node-red-dashboard

To start Node-Red either use the on-screen menus or from the command line enter:

node-red-start &

Once Node-Red is running the programming is done via the web interface at: //localhost:1880 or //your_Pi_ip_address:1880 .

To configure the TCP server, go to the Input nodes section and drag and drop the TCP in node. After the node is inserted double-click on it and edit the port and message settings.

nodered_tcp

To create a gauge Web dashboard, go to the dashboard nodes section and drag and drop the gauge node. After the node is inserted double-click on it and edit the dashboard group, labels and ranges.

nodered_tcp_gauge

For debugging and testing an output debug node is useful.

To access the Web dashboard enter: //localhost:1880/ui or //your_Pi_ip_address:1880/ui

TCP Python Server

The python TCP server will see the incoming Arduino message as a Unicode (UTF-8) text, so convert message to an integer use: thevalue = int(data.decode(“utf-8”)). Below is the full code.

import socket
import sys

HOST = '' # Symbolic name, meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ('Socket created')

#Bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print ('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1])
sys.exit()

print ('Socket bind complete')

#Start listening on socket
s.listen(10)
print ('Socket now listening')

#now keep talking with the client
while True:
#wait to accept a connection - blocking call
conn, addr = s.accept()
data = conn.recv(1024)
print ('Connected with ' + addr[0] + ':' + str(addr[1]) + " " )
thevalue = int(data.decode("utf-8"))
print ("Value: ", thevalue)

s.close(

Summary

In our final application we mounted the Arduino module outside and we powered it with a small solar charger. We also include a humidity value with the temperature, and we used a QR code that linked to our web page.

Control Lights with TV Remotes

Our TV remotes control most of our entertainment like the TV, DVD player and Kodi box. We thought that it would be useful if the same TV remotes could also turn on powered devices like the lights so that we could get to the kitchen or bathroom while we’re watching a movie.

We setup our project to work with 2 different TV remotes, and we selected 2 push buttons on the remotes that we not being used in our home entertainment arrangement.

For this project we used 2 small Arduino programs. The first program we used to find TV remote IR codes and the second program used our codes to control the light switch.

The equipment we used:

Power Switch

The PowerTail II switch is an isolated DC-actuated power cord (NO or NC) for controlling power to 120VAC appliances with a 2 wire input.

ir_switch_powertail

An Arduino Power Relay module or Shield is much cheaper than a Power Switch and the code for this project will be identical. We used the Power Tail Switch because we have one and we didn’t want to cut up our power cords.

The Setup

The Setup is very straightforward (see code for pin outs), one data pin for the IR module and one digital output for the relay or Power Tail Switch.

ir_switch_nano

Finding TV Remote IR Codes

The simple code below is used to catch IR codes:

 /*
 
 IR TEST PROGRAM

PINOUTS:

lEFT = DATA PIN
MIDDLE = gnd
RIGHT = 3.3 volts

*/

#include 

int RECV_PIN = 11;  //11;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Setup Complete");
}

void loop()
{
  if (irrecv.decode(&results))
    {
     Serial.println(results.value, HEX);
     irrecv.resume(); // Receive the next value
     delay(500);
     
    }
}

Final Code

We used 2 remotes, a newer Samsung, and an old Philips. On the Samsung we used the A and B buttons to turn the lights on and off. On the Philips we used the sharp and natural buttons.

Below is our final code:

 /*
 
TV Remote Control of Switches and Powered Devices
PINOUTS:

lEFT = DATA PIN
MIDDLE = gnd
RIGHT = 3.3 volts

*/

#include <IRremote.h>

int RECV_PIN = 11;  //11;

IRrecv irrecv(RECV_PIN);

decode_results results;

int swtpin = 10;

void setup()
{
  Serial.begin(9600);
  pinMode(swtpin, OUTPUT);
  irrecv.enableIRIn(); // Start the receiver
  Serial.println("Setup Complete");
}

void loop()
{
  if (irrecv.decode(&results))
    {
      switch (results.value) {
     case 0x94CC5A5E: 
       Serial.println("A pushed - light on");
       digitalWrite(swtpin, HIGH);
       break;     
     case 0x23B1EF88:
       Serial.println("B pushed - light off");
       digitalWrite(swtpin, LOW);
       break;    
         case 0x16892E01: 
       Serial.println("natural pushed - light on");
       digitalWrite(swtpin, HIGH);
       break;     
     case 0xDAD07464:
       Serial.println("sharp pushed - light off");
       digitalWrite(swtpin, LOW);
       break;   
     default:
       Serial.println(results.value, HEX);
      }
      irrecv.resume();
     delay(500);
     
    }
}

Handheld Gas Leak Monitor

There are some very low cost MQ-2 sensors  ($3-$5) that can be used to measure common combustible gases such as hydrogen, butane, methane, propane and liquid petroleum gas (LPG).

My goal for this project was to make a handheld monitor that we could use to measure potential leaks in our propane BBQ or natural gas leaks in and around our furnace.

mq2_setup

Setup

For our setup we used:

MQ2_circuitpng

Some duct tape can be used to secure the bread board to the USB battery unit. We used a low cost 4 digit display and we mounted it direct to the bread board.

Code

We were only interested in a “GAS” or “NO GAS” reading, so because of this our code was super simple.

#include <Arduino.h>
#include <TM1637Display.h>

// Module connection pins (Digital Pins)
#define CLK 2
#define DIO 3
TM1637Display display(CLK, DIO);

int smokeA0 = A0;
// Your threshold value
int sensorThres = 400;

void setup() {
  pinMode(smokeA0, INPUT);
  Serial.begin(9600);
  display.setBrightness(0x0f);
}

void loop() {
  int analogSensor = analogRead(smokeA0);

  Serial.print("Pin A0: ");
  Serial.println(analogSensor);
  display.showNumberDec(analogSensor, false);
  delay(1000);
}

If you want to get accurate gas measurements then you’ll need to do some calibration. We were only interested in a seeing something above a “clear air” reading.  For our setup a “clear air” reading was about 100-115. To test our project we used a butane lighter and we open it very quickly (<1 second).

Arduino Dust Monitor

There are some low cost analyzers  for about $15US. For home or test projects these sensors are great but I wouldn’t recommend them for any serious environmental studies. (For true air quality monitoring you need to compensate for temperature and humidity).

For this projects we used a 90mA PM2.5 Dust Sensor PPD42NS / PPD42NJ Sensor. These sensor need to be mounted upright, so we used some Meccano to build a simple stand.

The sensors have 5 pins, with the pinouts of:

  • Pin 1  => GND
  • Pin 3  => 5 VDC
  • Pin 4  => Data Pin

To see the results we used a 16×2 LCD shield.

OLYMPUS DIGITAL CAMERA

The product example samples every 30 seconds and it returns a value of particles per 1/100 of a cubic foot (pcs/0.01cf).

The returned values (in pcs/0.01cf) will need some validation but from our testing we found that :

  • 0-500 pcs/0.01cf = a clear room
  • 500-1500 pcs/0.01cf = a “fairly” clean room
  • 1500-4000 pcs/0.01cf = a room in need of dusting (but not super dusty)
  • 4000+ pcs/0.01cf = if you have allergies you may notice the room

Our code for the project is:

90mA PM2.5 Dust Sensor PPD42NS / PPD42NJ Sensor with an 16x2 LCD Shield

JST Pin 1 (Black Wire) => Arduino GND
JST Pin 3 (Red wire) => Arduino 5VDC
JST Pin 4 (Yellow wire) => Arduino Digital Pin 8
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

int pin = 28;
unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000;
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;
float maxcon = 0;

void setup() {
 Serial.begin(9600);
 pinMode(8,INPUT);
 starttime = millis();
 lcd.begin(16, 2);
}
void loop() {
 duration = pulseIn(pin, LOW);
 lowpulseoccupancy = lowpulseoccupancy+duration;
 if ((millis()-starttime) > sampletime_ms)
 {
 ratio = lowpulseoccupancy/(sampletime_ms*10.0); // Integer percentage 0=>100
 concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62;
 if (concentration > maxcon){ maxcon = concentration;}
 lcd.setCursor(0, 0);
 lcd.print("now: ");
 lcd.setCursor(5, 0);
 lcd.print(concentration);
 
 lcd.setCursor(0, 1);
 lcd.print("max: ");
 lcd.setCursor(5, 1);
 lcd.print(maxcon);

 Serial.print(" concentration: ");
 Serial.print(concentration);
 Serial.println(" pcs/0.01cf");
 Serial.print(" max concentration: ");
 Serial.print(maxcon);
 Serial.println(" pcs/0.01cf");
 lowpulseoccupancy = 0;
 starttime = millis();
 }
}