Browse our Blog. You will find multiple applications, solutions, code examples. Navigate using the tag cloud or search using specific criteria

Using Bootstrap toolkit for Arduino based PLC's

developing with HTML, CSS, and JS

Introduction

Bootstrap is the most popular HTML, CSS and JS library to build responsive web sites. Using this library we will be able to create a very well looking website that will show the data from our Arduino based PLCs. 

So if you are tired of the typical and boring look of your websites made with basic http, take a look on this post that will show you a new way to represent your web site dashboards.  

Odoo text and image block

Requirements

Application Architecture

Bootstrap web server requires that the client has internet access to visualize the web. This requirement is because the Arduino based PLC, in this case an M-Duino, will pass some script to the client and the clinet have to collected from a external server. If the client doesn't have internet access then the web server won't look as expected. 

Arduino HTTP server library will be able to create the HTTP content in our M-Duino. This content is an HTML dynamic file that is placed in our controller into the SRAM as a string. Of course this content have some limitations. The content will be limited for the SRAM. 


Software

Below is showed the final code for our industrial Arudino based controller:

/*
   Copyright (c) 2019 Boot&Work Corp., S.L. All rights reserved
   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.
   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef DEBUG
#define DEBUG 0
#endif
#ifdef MDUINO_PLUS
#include <Ethernet2.h>
#else
#include <Ethernet.h>
#endif
#include <HttpServer.h>
byte mac[] = {0xAF, 0xBE, 0xCD, 0xDC, 0xEB, 0xFA};
IPAddress ip(10, 10, 11, 16);
HttpServer http;
uint32_t counter = 0;
////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(9600UL);
#if DEBUG
  while (!Serial);
#endif
  Ethernet.begin(mac, ip);
  attachInterrupt(digitalPinToInterrupt(I0_6), count, RISING);
#if DEBUG
  Serial.print("IP address: ");
  Serial.println(Ethernet.localIP());
#endif
  http.begin();
#if DEBUG
  Serial.println("HTTP server started");
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  http.update();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void count() {
  ++counter;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void httpServerEvent(const HttpRequest &req, HttpResponse &res) {
#if DEBUG
  Serial.print("method: ");
  Serial.println(req.method);
  Serial.print("route: ");
  Serial.println(req.route);
  Serial.print("query string: ");
  Serial.println(req.queryString);
  Serial.print("body: ");
  Serial.println(req.body);
#endif
  if (req.route == "/") {
    serveRoot(req, res);
  } else if (req.route == "/status") {
    serveStatus(req, res);
  } else if (req.route == "/js") {
    serverScript(req, res);
  } else if (req.route == "/var/counter/reset") {
    counter = 0;
    res.text(String(counter));
  } else if (req.route == "/q0_0/HIGH") {
    digitalWrite(Q0_0, HIGH);
    res.text("ON");
  } else if (req.route == "/q0_0/LOW") {
    digitalWrite(Q0_0, LOW);
    res.text("OFF");
  } else if (req.route == "/q0_1/HIGH") {
    digitalWrite(Q0_1, HIGH);
    res.text("ON");
  } else if (req.route == "/q0_1/LOW") {
    digitalWrite(Q0_1, LOW);
    res.text("OFF");
  } else {
    // Send an error
    res.send("Not Found", "text/plain", 404, "Not Found");
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void serveRoot(const HttpRequest &req, HttpResponse &res) {
    // Send HTML content
    String html = "<!doctype html>"
    "<html>"
    "<head>"
    "<meta charset='utf-8'>"
    "<meta name='viewport' content='width=device-width,initial-scale=1,shrink-to-fit=no'>"
    "<title>Web monitor by Industrial Shields</title>"
    "<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css'>"
    "</head>"
    "<body>"
    "<div class='container'>"
    // TOOLBAR
    "<nav class='navbar navbar-expand-lg'>"
    "<a class='navbar-brand href='#'>Web monitor by Industrial Shields</a>"
    "</nav>"
    // VALUES TABLE
    "<div class='row'>"
    "<h3>Values</h3>"
    "</div>"
    "<div class='row'>"
    "<table class='table table-striped'>"
    "<thead>"
    "<tr>"
    "<th scope='col'>Name</th>"
    "<th scope='col' class='text-right'>Value</th>"
    "<th scope='col'>Actions</th>"
    "</tr>"
    "</thead>"
    "<tbody>"
    "<tr>"
    "<td>Millis</td>"
    "<td class='text-right' id='millis'></td>"
    "<td></td>"
    "</tr>"
    "<tr>"
    "<td>I0.5</td>"
    "<td class='text-right' id='i0_5'></td>"
    "<td></td>"
    "</tr>"
    "<tr>"
    "<td>I0.6 counter</td>"
    "<td class='text-right' id='counter'></td>"
    "<td><button type='button' class='btn btn-primary' onclick='resetCounter()'>Reset</td>"
    "</tr>"
    "</tbody>"
    "</table>"
    "</div>"
    // OUTPUTS ACTIONS
    "<div class='row'>"
    "<h3>Outputs</h3>"
    "</div>"
    "<div class='row'>"
    "<div class='col-4'>"
    "RED LED <span class='badge badge-primary' id='q0_0'></span>"
    "</div>"
    "<div class='col-4'>"
    "<button type='button' class='btn btn-danger' onclick='setQ0_0(\"HIGH\")'>ON</button>"
    "<button type='button' class='btn btn-secondary' onclick='setQ0_0(\"LOW\")'>OFF</button>"
    "</div>"
    "</div>"
    "<div class='row'>"
    "<div class='col-4'>"
    "GREEN LED <span class='badge badge-primary' id='q0_1'></span>"
    "</div>"
    "<div class='col-4'>"
    "<button type='button' class='btn btn-success' onclick='setQ0_1(\"HIGH\")'>ON</button>"
    "<button type='button' class='btn btn-secondary' onclick='setQ0_1(\"LOW\")'>OFF</button>"
    "</div>"
    "</div>"
    "</div>"
    "<script src='https://code.jquery.com/jquery-3.3.1.min.js'></script>"
    "<script src='https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js'></script>"
    "<script src='https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js'></script>"
    "<script src='/js'></script>"
    "</body>"
    "</html>";
    res.html(html);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void serverScript(const HttpRequest &req, HttpResponse &res) {
  String content = "function update() {"
    "$.get('/status', function(d){"
    "var s = d.split(' ');"
    "document.getElementById('millis').innerText = s[0];"
    "document.getElementById('i0_5').innerText = s[1];"
    "document.getElementById('counter').innerText = s[2];"
    "document.getElementById('q0_0').innerText = s[3];"
    "document.getElementById('q0_1').innerText = s[4];"
    "});"
    "}"
    "function resetCounter() {$.post('/var/counter/reset', function(d) {document.getElementById('counter').innerText = d;});}"
    "function setQ0_0(v) {$.post('/q0_0/' + v, function(d) {document.getElementById('q0_0').innerText = d;});}"
    "function setQ0_1(v) {$.post('/q0_1/' + v, function(d) {document.getElementById('q0_1').innerText = d;});}"
    "setInterval(update, 1000);";
  res.send(content, "application/javascript");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void serveStatus(const HttpRequest &req, HttpResponse &res) {
  String content;
  content += String(millis());
  content += ' ';
  content += String(digitalRead(I0_5) ? "ON" : "OFF");
  content += ' ';
  content += String(counter);
  content += ' ';
  content += String(digitalRead(Q0_0) ? "ON" : "OFF");
  content += ' ';
  content += String(digitalRead(Q0_1) ? "ON" : "OFF");
  res.text(content);
}

 
 

Do you want more information?

Open Source technology allows you to develop your installations.

Just fill the form and we will contact you as soon as we can.

Send