MySQL with Arduino and Node-Red

In this blog I would like to document a project that I did with my kids. The goal of the project was to learn SQL in a couple of different environments.

mysql_overview

We did most of our initial testing/learning directly on the MySQL server. Once we got everything worked out we moved to Arduino, then Node-Red.

For our MySQL testing we used alwaysdata.com which has a free low use account. They run MariaDB which looks exactly like MySQL.

 

MySQL Setup

The plan was to have the Arduino module write 3 values:

  1. randint – a random integer from 1-100
  2. saw – a saw tooth integer from 0-100
  3. sstatus – a text value of : HIGH, OKAY or LOW

sample_data

We didn’t want to generate a time stamp from Arduino, instead we wanted MySQL to generate it. Our SQL structure was:

datal_structure

The field “thetime” was defined as a timestamp with CURRENT_TIMESTAMP as the default. By doing this we only needed to INSERT the Arduino data and MySQL would add the current timestamp.

insert_test

After the Arduino Tables was created and tested we were able to start inserting data from Arduino.

 

Arduino and MySQL

There is an excellent MySQL library for Arduino, that can be added via the Arduino IDE “Manage Libraries” option.

Our Arduino code wrote the 3 values to MySQL every 10 seconds.

/*
  MySQL Connector/Arduino Example : connect by wifi
*/
#include <ESP8266WiFi.h>           // Use this for WiFi instead of Ethernet.h
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>

IPAddress server_addr(111,222,111,111);  // IP of the MySQL *server* here
char user[] = "yourusername";              // MySQL user login username
char password[] = "yourpassword";        // MySQL user login password

// WiFi card example
char ssid[] = "xxxxx";         // your SSID
char pass[] = "xxxxx";     // your SSID Password

WiFiClient client;                 // Use this for WiFi instead of EthernetClient
MySQL_Connection conn(&client);
MySQL_Cursor* cursor;

int saw = 0;

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

  // Begin WiFi section
  Serial.printf("\nConnecting to %s", ssid);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  // print out info about the connection:
  Serial.println("\nConnected to network");
  Serial.print("My IP address is: ");
  Serial.println(WiFi.localIP());

  Serial.print("Connecting to SQL...  ");
  if (conn.connect(server_addr, 3306, user, password))
    Serial.println("OK.");
  else
    Serial.println("FAILED.");
  
  // create MySQL cursor object
  cursor = new MySQL_Cursor(&conn);
}

void loop()
{
  // Sample insert query
  //
  char INSERT_SQL[] = "INSERT INTO datal (randint, saw, sstatus) VALUES ('%d','%d','%s')";
  char query[128];
  int randint = random(100);


saw++;
if (saw == 100){
  saw = 0;
}

  if (randint <= 10){
     sprintf(query, INSERT_SQL, randint, saw, "LOW");
  } else if (randint >= 90){
     sprintf(query, INSERT_SQL, randint, saw, "HI");
  } else {
     sprintf(query, INSERT_SQL, randint, saw, "OKAY");
  }
  
  Serial.println(query);

  if (conn.connected())
    cursor->execute(query);


  // Sample select query - Get the last 2 values and show them 
  // Table: arduino1 - this is written to from Node-Red 

  int arddata;
  // Initiate the query class instance
  row_values *row = NULL;
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);

  char squery[] = "SELECT thetime,arddata FROM arduino1 ORDER BY thetime DESC limit 2;";
  cur_mem->execute(squery);
  // Fetch the columns (required) but we don't use them.
  column_names *columns = cur_mem->get_columns();

  do {
    row = cur_mem->get_next_row();
    if (row != NULL) {
      //thetime = (row->values[0]);
      arddata = atoi(row->values[1]);
      Serial.print("Time: "); Serial.print(row->values[0]); Serial.print(" data: "); Serial.println(arddata);
      
    }
  } while (row != NULL);
  delete cur_mem;
  
  delay(10000);
  
}

 

MySQL Views

The table(s) that we created were nice and simple for Arduino data, but they couldn’t be used directly for any types of statistics like daily/hourly/minute averages/maxs or minimums. So we created some MySQL views.

The first things that we needed to do was create some “time” columns like HOUR and MINUTE.

CREATE VIEW v_raw as 
 SELECT HOUR(thetime) as HOUR, 
   MINUTE(thetime) as MINUTE, 
   randint, saw, sstatus from datal 
   order by thetime DESC

This SQL statement creates a view (v_raw)  that shows the hour, minute fields with data ordered from newest to oldest. The query of : SELECT  * FROM v_raw; gives:

v_raw

We then created a number of statistic views like:

CREATE VIEW v_min AS 
  SELECT HOUR(thetime) as HOUR, MINUTE(thetime) as MINUTE, 
    AVG(randint), AVG(saw) 
   from datal 
     GROUP BY HOUR,MINUTE ORDER BY thetime LIMIT 720

This gave us some minute averages:

v_min

 

Node-Red with MySQL

The component node-red-node-mysql can be added manually or via the “Manage Palettes” option.

node-red-node-mysql

For our project we wanted to show:

  • Last 100 Arduino values
  • Latest Average Minute Values
  • Latest Average Hourly Value

Then we wanted to Insert a new 0/1 value that could be read back in the Arduino. This inserted value could be used to turn on a relay connected to the the Arduino (like a start a fan, turn on a light etc.)

The logic used Dashboard buttons (to select an action).  MySQL nodes do the SELECT or INSERT command, and a Dashboard Table to show the results.

mysql_nodered_logic

The buttons are configured to pass the SQL views statement to the MySQL nodes, with the results showing in a Dashboard table node.

nr_v_min

After the logic is complete, use the Deploy button to make the logic live. The web dashboards can be viewed at: http://yourNodeRed_IP:1880/ui . Below is an example of 1) Minute Averages, and 2) Last 100 (raw values).

 

Final Comments

For this project we kept things simple, and used tables to show the results. As a next step it would be good to show the results in a trend chart. In a previous blog I looked at putting SQLite into a Node-Red chart. I would use this technique with MySQL data.

 

 

 

Arduino Yún for IoT

There are some great Internet of Things hardware platforms, such as Raspberry Pi’s, ESP-32 based Arduino modules, Particle and Beaglebone to name just a few. Each of these systems have their strengths and weakness. Some are strong on the hardware side, like the Arduino modules, and others excel on the programming side like the Raspberry Pi.  

The Yún is somewhat unique in that it’s a module with two processors, one that supports standard Arduino programming and a second processor that supports Linux and the OpenWrt wireless stack. The Yún ($59) has an Arduino Uno form factor and there are clones like the LinkIt Smart 7688 Duo ($18) in an Arduino Nano form factor.

yun_overview

In this blog I wanted to document some of key feature and functions that I worked through, namely:

  • moving file – scp and ftp
  • Python bridging to Arduino
  • uhttpd Web Server – with Python CGI
  • Yún REST API
  • MQTT
  • Yún mailbox

Yún Overview

The Yún, now in revision 2, seems to have been somewhat overlooked because of the all the low cost ESP-8266 and ESP32 based Arduino modules starting around $2.

Some the interesting features of the Yún include:

  • Arduino code can launch and get feedback from Linux apps
  • A bridge library allows Linux programs and Arduino to share data
  • Arduino libraries for:
    • Web client
    • Web server
    • Mailbox to Linux
  • Yún has a lightweight web server, uhttpd, that can be used to Python, PHP, Lua CGI web programs
  • Yún has a read/write REST API web service

Getting Started

The Arduino side of the Yún is available “out of the box” like any other Arduino module when you connect a USB cable into the module.

The Linux side however requires some configuration. Please see one of the guides on the Linux setup. Once your module is connected to your network, the Yun webserver can be used to configure features and add software components.

yun_software1

Another option for loading software is to use the opkg package manager from an SSH connection.

yun_opkg

So for example to install nano, the simple text editor, enter:

 opkg install nano

Moving File and Working in OpenWrt Linux

The OpenWrt Linux isn’t loaded with with an X-windows environment and this means that you can not run idle or leafpad etc. to do easy editing of program files. Nano is a good command line text editor but it’s not the same as a windows based editor.

To move files between a PC and OpenWrt you have some options. The two that I like are:

  • scp – secure copy, this is built in both OpenWrt and Microsoft Window 10
  • ftp – file transfer protocol. Needs to be installed in OpenWrt.

There are a few ftp servers that could be installed in OpenWrt, vsftp is a lightweight option and it can be installed by:

opkg update
opkg install vsftpd

Once vsftpd is installed it needs to be enabled, this can be done from the command line or via the web interface.

yun_ftp_start.png

Yún Bridge

The Yun Arduino bridge library allow variables to be passed between the Arduino code and a Python program. Below is an example that writes two random variables available, and it creates a “bridge1” variable that can be written from the Python side.

// Simple Yun Bridge Example
//

#include <Bridge.h>
// create a bridge variable to get remote data
char bridge_Value[10];

void setup()
{
    Bridge.begin();     // this launches /usr/bin/run-bride on Linino
}

void loop()
{    
    // create 2 random bridge values, that are sourced from the Arduino
    Bridge.put("random1", String(random(1, 100)));
    Bridge.put("random2", String(random(1, 100)));
    // Called the bridge value "bridge1". This is the name used on the Python side
    Bridge.get("bridge1", bridge_Value, 6);
    delay(1000);  
}

An example to read/write in Python:


#!/usr/bin/python

import sys

sys.path.insert(0, '/usr/lib/python2.7/bridge/')

from bridgeclient import BridgeClient as bridgeclient
value = bridgeclient()

message = value.get("random1") # get a value from Arduino

print "Random1: ", message

value.put("bridge1","1111")  # set a value to Arduino

Yún uhttpd web server

The uhttp web server is used for Yun setup and configuration. This web server can also be used to for custom static pages and user web apps. To view/modify the web server settings:

nano /etc/config/uhttpd

Within this config file, you can enable custom web applications by defining an interpreter:

# List of extension->interpreter mappings.
# Files with an associated interpreter can
# be called outside of the CGI prefix and do
# not need to be executable.
# list interpreter ".php=/usr/bin/php-cgi"
# list interpreter ".cgi=/usr/bin/perl"
list interpreter ".py=/usr/bin/python

# Lua url prefix and handler script.
# Lua support is disabled if no prefix given.
# option lua_prefix /luci
# option lua_handler /usr/lib/lua/luci/sgi/uhttpd.lua

The default directory for user programs is: /www/cgi-bin

Python CGI – Get Values

To read the Arduino bridge values in a Python CGI program, add a file to the /www/cgi-bin directory. For my example I called the file p1.py :


#!/usr/bin/python

import sys
import cgi

sys.path.insert(0, '/usr/lib/python2.7/bridge/')

from bridgeclient import BridgeClient as bridgeclient
value = bridgeclient()

print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Python CGI Bridge</title>'
print '</head>'
print '<body>'
print '<h2>Python CGI Bridge</h2>'
print 'Random Value1: ' + value.get("random1")
print 'Random Value2: ' + value.get("random2")
print '</body>'
print '</html>'

To run the python script on the web page you will need to change the file right to executable:

chmod +x p1.py

You can debug and see output from the command line.


root@yun1:/www/cgi-bin# ./p1.py
Content-type:text/html

<html>
<head>
<title>Python CGI Bridge</title>
</head>
<body>
<h2>Python CGI Bridge</h2>
Random Value1: 13
Random Value2: 24
</body>
</html>

If the output looks good, try the app from the Web page:

CGI_bridge1

Python CGI – Put Values

There are a number of methods that can be used to send user input from a web page. A simple approach is to use a form. The form data can be read from the cgi.FieldStorage object, using a form.getvalue() call.

#!/usr/bin/python

# Import modules for CGI handling
import cgi
import sys

sys.path.insert(0, '/usr/lib/python2.7/bridge/')
from bridgeclient import BridgeClient as bridgeclient
value = bridgeclient()

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
bridge1 = form.getvalue('bridge1')
if bridge1 != "" :
    value.put("bridge1",bridge1)


print "Content-type:text/html\r\n\r\n"
print """
<html>
<head>
<title>Python CGI - Put Bridge Value</title>
</head>
<body>
<h2>Python CGI Form - Put Bridge Value</h2>
<form action = "/cgi-bin/p2.py" method = "post">
Enter BRIDGE1 value: <input type = "text" name = "bridge1"><br />

<input type = "submit" value = "Submit" />
</form>
</body>
</html>"""

 

The web page will call itself when the submit button is pressed.

CGI_bridge2

Yún REST API

The Yún REST API is a web service that allow remote users and web browsers to view and set bridge values. I found the REST API to be a good tool for testing my Web CGI and Python applications

To view all bridge variables enter: http://yourYun_IP/data/get

yun_rest_1

To get a specific bridge value enter:  http://yourYun_IP/data/get/my_bridge_value

yun_rest_2

To put a bridge value enter: http://yourYun_IP/data/put/my_bridge_value/value 

yun_rest_3

IoT Connections – MQTT

For Internet of Things (IoT) projects you need to pass data from the Arduino and some server. The communications and the server would be something like MQTT or Redis.

The Yún does not have direct access to the Wifi or ethernet port so the standard Arduino libraries for MQTT or Redis etc. will not work. An alternative approach is load the protocol’s command line client on the Linux side and then Arduino can shell out to the Linux tool.

For example to load the  Mosquitto MQTT command line tools:

opkg update
opkg install mosquitto-client

To test MQTT publishing to a topic (mytag1) with a message of 249 on remote client (192.168.0.116) :

mosquitto_pub -h 192.168.0.116 -u username -P password -t mytag1 -m 249

To remotely subscribe to

mosquitto_sub -h 192.168.0.116 -u username -P password -t mytag1

An example of sending out four MQTT messages in Arduino:

/*
Shell out to pass values to a MQTT command line pub
*/
#include <Process.h>

void setup() {
  Bridge.begin();	// Initialize the Bridge
  Serial.begin(9600);	// Initialize the Serial

  // Wait until a Serial Monitor is connected.
  while (!SerialUSB);
}

void loop() {
  Process p;
  String thecmd;
  String strval = String( random(0,100));
  // create a string with host, username and password, -t is for the topic
  String theparams = "-h 192.168.0.116 -u pete -P pete -t ";
  int numtopics = 4;
  String topics[4] = {"tag1","tag2","tag3","tag4"};

  for (int i=0; i < numtopics ; i++) {
    strval = String( (i*100) + random(1,99)); // create a random value - 0,100+,200+,300+
    thecmd = "mosquitto_pub " + theparams + topics[i] + " -m " + strval;
    Serial.println(thecmd);
    p.runShellCommand(thecmd);
    // do nothing until the process finishes, so you get the whole output:
    while (p.running());
  }
  // Wait 5 seconds and repeat
  delay(5000);  // wait 5 seconds before you do it again
}

It is also possible to create some bridge variables and pass them to a Python program that could do the MQTT communications.

Yún Mailbox

At present the mailbox only works in one direction, and this into the Arduino. Both the REST web interface and Python have writing functionality but no read capabilities (on the forums this has been identified, so a future revision may add this).

To write using REST:

http://yun_ip/mailbox/mymessagetext

To write using Python:


import sys
sys.path.insert(0, '/usr/lib/python2.7/bridge')
from bridgeclient import BridgeClient
client = BridgeClient()
client.mailbox("my_message")

The Arduino code to read message:

// Mailbox Read Example
//
#include <Mailbox.h>

void setup() {

  // Initialize Bridge and Mailbox
  Bridge.begin();
  Mailbox.begin();

  // Initialize Serial
  SerialUSB.begin(9600);

  // Wait until a Serial Monitor is connected.
  while (!SerialUSB);
  SerialUSB.println("Mailbox Read Message\n");
}

void loop() {
  String message;

  // if there is a message in the Mailbox
  if (Mailbox.messageAvailable()) {
    // read all the messages present in the queue
    while (Mailbox.messageAvailable()) {
      Mailbox.readMessage(message);
      SerialUSB.println(message);
    }

    SerialUSB.println("Waiting 10 seconds before checking the Mailbox again");
  }
  // wait 30 seconds
  delay(10000);
}

I’m not totally sure when I’d use a mailbox. The mailbox is a generic message and it’s not queued (only 1 message) so I think that using the standard bridging of values with get/put is more useful.

Final Comments

The Yun is missing a lot of networking libraries that are available with the ESP-8266 and ESP32 family of Arduino modules. In some cases like with MQTT that was a good Linux command line tool that could be used, but in cases like where you want to connect to a Redis server, you might have some challenges.

I really liked Yun’s built in uhttpd web server, this is far superior to the ESP-8266 Arduino web server library calls.

I found that putting logic into a combination of Python and Arduino could be a little confusing, but for projects with a lot of text or json data using Python would be a real plus. Also for projects where multitasking is required use the Linux process would be ideal.

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.

 

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();
 }
}

Animated Bike Light

For this project we wanted to create a portable animated light that we could mount below our bike seat or attach it to a knapsack. The parts that we used were:

parts

We happened to have a Squarewear module from some past work. This is a nice module for wearable projects because it has a built-in rechargeable battery and easy to solder connections. However other small Arduino modules could also be used.

The case that we used we got from a local dollar store (for $1) and it had a hard back and neoprene front pocket.  The four wires that we soldered to the LED Matrix were fairly stiff so we bent them over the lip of the neoprene pocket. The Squarewear module was slipped in behind for easy access to its power switch.

mounting

The Adafruit 8×8 matrix has four connections: SDA, SCL, VCC and GND. In the arduino code you will need to include the libraries:

  • Adafruit_GFX.h
  • Adafruit_LEDBackpack.h

There are a lot of options on what you could display. Our first example used a set of squares that changed sizes.

Our second example used some “old school” animated alien images.

In our final project we used the button on the Squarewear to trigger four different modes:

  • Alien mode
  • Square mode (best for biking)
  • Scroll the temperature
  • Show some text

Have fun.

//****************************************************/
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
#include <PciManager.h>
#include <PciListenerImp.h>

#define ulong unsigned long
#define uchar unsigned char
#define pinButton 4
#define temp_sensor A1

PciListenerImp listener(pinButton, onPinButtonChange);

uchar buttonPressed = 10; //4 = onboard button
//-----------------------------------------------------------
void onPinButtonChange(byte changeKind) {
  static ulong t = 0;
  if (changeKind == 1 && millis() > t + 250) {
    t = millis();
    buttonPressed = 1;    
  }
}

Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
//-----------------------------------------------------------
void setup() {
  pinMode(pinButton, INPUT);
  digitalWrite(pinButton, HIGH);
  PciManager.registerListener(pinButton, &listener); 
  
  
  matrix.begin(0x70);  // pass in the address
}
//-----------------------------------------------------------
void loop() {
  // Make 3 modes, 1) Temperature, 2) Bike, 3) Pictures
  
   buttonPressed = 0;
  loop_pic();
  
  buttonPressed = 0;
  loop_temp();

  buttonPressed = 0;
  loop_bike();
  
  buttonPressed = 0;
  loop_text();

}
//----------------------------------------
void loop_temp() {
  // Loop thru showing the temperature until the button is pressed
  
  float temp;
  
  matrix.setTextWrap(false); 
  matrix.setTextSize(0.5);
  matrix.setRotation(3);
  while(!buttonPressed) { 
    // convert to celcius
    temp = (float)analogRead(temp_sensor);
    temp = (temp * 3.3 / 1024 - 0.5) / 0.01;

    for (int8_t x=0; x>=-20; x--) {
      matrix.clear();
      matrix.setCursor(x,0);
      matrix.print(int(temp) );
      matrix.print("c");
      matrix.writeDisplay();
      delay(300);
      if(buttonPressed)  break;
    }
  }
}
//-------------------------------------------------------------
void loop_bike() {
  // Loop with a visible biking safe pattern until button pushed
  while(!buttonPressed) {
  
    matrix.clear();
    matrix.fillRect(3,3, 2,2, LED_ON);
    matrix.writeDisplay();  // write the changes we just made to the display
        if(buttonPressed)  break;
    delay(250);
    
    matrix.clear();
    matrix.fillRect(2,2, 4,4, LED_ON);
    matrix.writeDisplay();  // write the changes we just made to the display
    if(buttonPressed)  break;
    delay(250);
    
    matrix.clear();
    matrix.fillRect(1,1, 6,6, LED_ON);
    matrix.writeDisplay();  // write the changes we just made to the display
    if(buttonPressed)  break;
    delay(250);
    
    matrix.clear();
    matrix.fillRect(0,0, 8,8, LED_ON);
    matrix.writeDisplay();  // write the changes we just made to the display
    if(buttonPressed)  break;
    delay(250);
    
  }
} 
// ------------------------------------------------------------
const uint8_t PROGMEM alien[21][8] = {
{
  B00011000, // This is the first frame for alien #1
  B00111100, // If you squint you can kind of see the
  B01111110, // image in the 0's and 1's.
  B11011011,
  B11111111,
  B00100100,
  B01011010,
  B10100101	},

  {
  B00011000, // This is the second frame for alien #1
  B00111100,
  B01111110,
  B11011011,
  B11111111,
  B00100100,
  B01011010,
  B01000010 },

  {
  B00011000, B00111100, B01111110, B11011011, B11111111, B00100100, B01011010, B10100101 },
  {
  B00011000, B00111100, B01111110, B11011011, B11111111, B00100100, B01011010, B01000010 },

  {
  B00000000, // First frame for alien #2
  B00111100,
  B01111110,
  B11011011,
  B11011011,
  B01111110,
  B00100100,
  B11000011 },

  {
  B00111100, // Second frame for alien #2
  B01111110,
  B11011011,
  B11011011,
  B01111110,
  B00100100,
  B00100100,
  B00100100 },

  {
  B00000000, B00111100, B01111110, B11011011, B11011011, B01111110, B00100100, B11000011 },
  {
  B00111100, B01111110, B11011011, B11011011, B01111110, B00100100, B00100100, B00100100 },

  {
  B00100100, // First frame for alien #3
  B00100100,
  B01111110,
  B11011011,
  B11111111,
  B11111111,
  B10100101,
  B00100100},

  {
  B00100100, // Second frame for alien #3
  B10100101,
  B11111111,
  B11011011,
  B11111111,
  B01111110,
  B00100100,
  B01000010 },

  {
  B00100100, B00100100, B01111110, B11011011, B11111111, B11111111, B10100101, B00100100 },
  {
  B00100100, B10100101, B11111111, B11011011, B11111111, B01111110, B00100100, B01000010 },
  
  {
  B00111100, // First frame for alien #4
  B01111110,
  B00110011,
  B01111110,
  B00111100,
  B00000000,
  B00001000,
  B00000000 },

  {
  B00111100, // Second frame for alien #4
  B01111110,
  B10011001,
  B01111110,
  B00111100,
  B00000000,
  B00001000,
  B00001000 },

  {
  B00111100, // Third frame for alien #4 (NOT a repeat of frame 1)
  B01111110,
  B11001100,
  B01111110,
  B00111100,
  B00000000,
  B00000000,
  B00001000 },
 
  {
  B00111100, // Fourth frame for alien #4 (NOT a repeat of frame 2)
  B01111110,
  B01100110,
  B01111110,
  B00111100,
  B00000000,
  B00000000,
  B00000000},

  {
  B00111100, B01111110, B00110011, B01111110, B00111100, B00000000, B00001000, B00000000 },
  {
  B00111100, B01111110, B10011001, B01111110, B00111100, B00000000, B00001000, B00001000 },
  {
  B00111100, B01111110, B11001100, B01111110, B00111100, B00000000, B00000000, B00001000 },
  {
  B00111100, B01111110, B01100110, B01111110, B00111100, B00000000, B00000000, B00000000 },
  
};

 
 
//-------------------------------------------------------------
static const uint8_t PROGMEM
  smile_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10100101,
    B10011001,
    B01000010,
    B00111100 },
    
  wink_bmp[] =
  { B00111100,
    B01000010,
    B10100001,
    B10000001,
    B10100101,
    B10011001,
    B01000010,
    B00111100 },
    
  lsmile_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10100001,
    B10011001,
    B01000010,
    B00111100 },
    
   rsmile_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10000101,
    B10011001,
    B01000010,
    B00111100 };

//----------------------------------------
void loop_pic() {
  
  while(!buttonPressed) {
    matrix.clear();
    matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
    matrix.writeDisplay();
    delay(1500);
    if(buttonPressed)  break;
    
    matrix.clear();
    matrix.drawBitmap(0, 0, wink_bmp, 8, 8, LED_ON);
    matrix.writeDisplay();
    delay(500);
    if(buttonPressed)  break;
    
    matrix.clear();
    matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
    matrix.writeDisplay();
    delay(1500);
    if(buttonPressed)  break;
    
    matrix.clear();
    matrix.drawBitmap(0, 0, lsmile_bmp, 8, 8, LED_ON);
    matrix.writeDisplay();
    delay(1000);
    
    matrix.clear();
    matrix.drawBitmap(0, 0, rsmile_bmp, 8, 8, LED_ON);
    matrix.writeDisplay();
    delay(1000);
    if(buttonPressed)  break;
    
    matrix.clear();
    matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_ON);
    matrix.writeDisplay();
    delay(1500);
    
    matrix.setRotation(3);
    for (int i=0; i< 21; i++) {
      matrix.clear();
      matrix.drawBitmap(0, 0, alien[i], 8, 8, LED_ON);
      matrix.writeDisplay();
      delay(250);
      if(buttonPressed)  break;
    }
  }
}
//----------------------------------------
void loop_text() {
  // Loop thru showing the temperature until the button is pressed
   
  matrix.setTextWrap(false); 
  matrix.setTextSize(1);
  matrix.setRotation(3);
  char thetext[] = "Hello";
  while(!buttonPressed) { 
 
    for (int8_t x=0; x>=-40; x--) {
      matrix.clear();
      matrix.setCursor(x,0);
      matrix.print(thetext);
       matrix.writeDisplay();
      delay(300);
      if(buttonPressed)  break;
    }
  }
}