domingo, 20 de agosto de 2017

Tutorial #17 ESP8266 (Parte7) – Integrar MQTT con MySQL usando Python

Este es el séptimo tutorial de IOT (internet de las cosas) usando MQTT en un ESP8266; en estos videos (Parte A y B) explico cómo integrar MQTT (usando el bróker CloudMQTT) con MySQL, para eso vamos a usar Python y dos librerías, “paho-mqtt 1.3.0” para conectarse con MQTT y “MySQL-python 1.2.5” para trabajar con la base de datos. En la parte B del tutorial termino de explicar cómo crear la base de datos usando la herramienta phpMyAdmin incluida en el servidor local WAMP “Uniform Server – Coral 8.9.2”; y agrego lo que falta del código de Python como trabajar con la base de datos.

Parte A:


Parte B:


tutorial17.py:

#!/usr/bin/env python 1
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt
import sys

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Conectado - Codigo de resultado: "+str(rc))

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe("/#")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

try:
    client.connect("m13.cloudmqtt.com", 11948, 60)
except:
    print("No se pudo conectar con el MQTT Broker...")
    print("Cerrando...")
    sys.exit()
    
client.username_pw_set("lqeamtbn", "vh0cU_Vcszxp")

try:
    client.loop_forever()
except KeyboardInterrupt:  #precionar Crtl + C para salir
    print("Cerrando...")

tutorial17b.py:

#!/usr/bin/env python 1
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt
import sys
import MySQLdb

# Abrir conexión con bases de datos
try:
    db = MySQLdb.connect("127.0.0.1","root","root","tutorial17")
except:
    print("No se pudo conectar con la base de datos")
    print("Cerrando...")
    sys.exit()

# Preparando cursor
cursor = db.cursor()

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    print("Conectado - Codigo de resultado: "+str(rc))

    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe("/#")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))
    lista = msg.topic.split("/")

    sql = """INSERT INTO `tutorial17`.`tabla` (`id`, `usuario`, `topic`, `mensaje`, `fecha`) VALUES (NULL, '""" + lista[1]+ """', '""" + lista[2] + """', '""" + str(msg.payload) + """', CURRENT_TIMESTAMP);"""

    try:
        # Ejecutar un comando SQL
        cursor.execute(sql)
        db.commit()
        print("Guardando en base de datos...OK")
    except:
        db.rollback()
        print("Guardando en base de datos...Falló")
        
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

try:
    client.connect("m13.cloudmqtt.com", 11948, 60)
except:
    print("No se pudo conectar con el MQTT Broker...")
    print("Cerrando...")
    db.close()
    sys.exit()   
    
client.username_pw_set("lqeamtbn", "vh0cU_Vcszxp")

try:
    client.loop_forever()
except KeyboardInterrupt:  #precionar Crtl + C para salir
    print("Cerrando...")
    db.close()

Python y Librerías:


Enlaces externos:

http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html

sábado, 19 de agosto de 2017

Tutorial #16 ESP8266 (Parte6) – Gráficos en tu Dashboard MQTT usando Highcharts

En este nuevo tutorial sobre IOT (internet de las cosas) usando ESP8266, voy a explica como agregarle un gráfico al dashboard MQTT que vimos en el tutorial anterior. Para eso vamos a usar JavaScript y dos librerías de Highcharts.


tutorial16.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Tutorial 16</title>
    <script src='mqttws31.js' type='text/javascript'></script> 
    <!-- https://api.cloudmqtt.com/sso/js/mqttws31.js -->
    <script src="raphael-2.1.4.min.js"></script>
    <script src="justgage.js"></script>
    <script src="https://code.highcharts.com/stock/highstock.js"></script>
    <script src="https://code.highcharts.com/stock/modules/exporting.js"></script>    
  </head>
  <style type="text/css">
    .a200x160px {
      width: 200px;
      height: 160px;
    }
    img {
      margin-left: 75px;
    }

    .switch {
      position: relative;
      display: inline-block;
      width: 120px;
      height: 68px;
    }

    .switch input {display:none;}

    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #ccc;
      -webkit-transition: .4s;
      transition: .4s;
    }

    .slider:before {
      position: absolute;
      content: "";
      height: 52px;
      width: 52px;
      left: 8px;
      bottom: 8px;
      background-color: white;
      -webkit-transition: .4s;
      transition: .4s;
    }

    input:checked + .slider {
      background-color: red;
    }

    input:focus + .slider {
      box-shadow: 0 0 1px #2196F3;
    }

    input:checked + .slider:before {
      -webkit-transform: translateX(52px);
      -ms-transform: translateX(52px);
      transform: translateX(52px);
    }

    .slider.round {
      border-radius: 68px;
    }

    .slider.round:before {
      border-radius: 50%;
    }

    input[type=range] {
      height: 26px;
      -webkit-appearance: none;
      margin: 10px 0;
      width: 120px;
    }
    input[type=range]:focus {
      outline: none;
    }
    input[type=range]::-webkit-slider-runnable-track {
      width: 100%;
      height: 14px;
      cursor: pointer;
      animate: 0.2s;
      box-shadow: 1px 1px 1px #50555C;
      background: #50555C;
      border-radius: 14px;
      border: 0px solid #000000;
    }
    input[type=range]::-webkit-slider-thumb {
      box-shadow: 0px 0px 0px #000000;
      border: 0px solid #000000;
      height: 20px;
      width: 40px;
      border-radius: 12px;
      background: green;
      cursor: pointer;
      -webkit-appearance: none;
      margin-top: -3px;
    }
    input[type=range]:focus::-webkit-slider-runnable-track {
      background: #50555C;
    }
   
    input[type=range]:focus::-ms-fill-lower {
      background: #50555C;
    }
    input[type=range]:focus::-ms-fill-upper {
      background: #50555C;
    }

    #container {
      width: 600px;
      height: 300px;
    }
  </style>
  <body>
      <div id="gauge" class="a200x160px"></div>
      <div>
        <img id="imgPulsador" src="nopresionado.png">
      </div>
      <div>
         <svg width="100" height="75" viewBox="0 0 640 480">
         <defs>
          <linearGradient id="svg_6" x1="0" y1="0" x2="1" y2="0">
           <stop stop-color="#bfbfbf" offset="0"/>
           <stop stop-color="#404040" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_11" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop id="led1" stop-color="#000000" stop-opacity="0.992188" offset="0"/>
           <stop stop-color="#820101" stop-opacity="0.988281" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_14" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop stop-color="#ffffff" stop-opacity="0.996094" offset="0"/>
           <stop stop-color="#d30606" stop-opacity="0.984375" offset="0.703125"/>
          </linearGradient>
         </defs>
         <g>
          <title>Layer 1</title>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" cx="320" cy="240" r="196.125" id="svg_3" fill-opacity="0.77" transform="rotate(90, 320, 240)"/>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" fill-opacity="0.64" cx="319.252837" cy="239.999045" r="160" id="svg_7"/>
          <circle fill="url(#svg_11)" stroke-width="17.5" stroke-linecap="round" cx="320.000535" cy="240.001698" r="150" id="svg_8"/>
          <ellipse fill="url(#svg_14)" stroke-width="17.5" stroke-linecap="round" cx="250.179609" cy="170.124194" rx="75.675959" ry="44.402987" id="svg_20" transform="rotate(-47.7626, 250.18, 170.125)"/>
         </g>
        </svg>
        <label class="switch">
          <input type="checkbox" onclick='OnOff2()'>
          <span class="slider round"></span>
        </label>
      </div>
      <div>
         <svg width="100" height="75" viewBox="0 0 640 480">
         <defs>
          <linearGradient id="svg_26" x1="0" y1="0" x2="1" y2="0">
           <stop stop-color="#bfbfbf" offset="0"/>
           <stop stop-color="#404040" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_211" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop id="led2" stop-color="rgb(0, 0, 0)" stop-opacity="0.992188" offset="0"/>
           <stop stop-color="#018201" stop-opacity="0.988281" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_214" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop stop-color="#ffffff" stop-opacity="0.996094" offset="0"/>
           <stop stop-color="#06d306" stop-opacity="0.984375" offset="0.703125"/>
          </linearGradient>
         </defs>
         <g>
          <title>Layer 1</title>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" cx="320" cy="240" r="196.125" id="svg_23" fill-opacity="0.77" transform="rotate(90, 320, 240)"/>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" fill-opacity="0.64" cx="319.252837" cy="239.999045" r="160" id="svg_27"/>
          <circle fill="url(#svg_211)" stroke-width="17.5" stroke-linecap="round" cx="320.000535" cy="240.001698" r="150" id="svg_28"/>
          <ellipse fill="url(#svg_214)" stroke-width="17.5" stroke-linecap="round" cx="250.179609" cy="170.124194" rx="75.675959" ry="44.402987" id="svg_220" transform="rotate(-47.7626, 250.18, 170.125)"/>
         </g>
        </svg>
        <input type="range" id="myRange" min="0" max="1023"  onmouseup="enviarSalidaAnalogica()">
      </div>
      <div id="container"></div>
    <script>      
      usuario = 'placa2';
      contrasena = '12345678';

      var g = new JustGage({
        id: "gauge",
        min: 0,
        max: 50,
        title: "Temperatura ºC"
      });

      estadoDigital = "OFF";
      temperaturas = -1;

      function OnOff2(){
        if (estadoDigital == "OFF"){
          message = new Paho.MQTT.Message("ON");
          message.destinationName = '/' + usuario + '/salidaDigital'
          client.send(message);
        }
        else if (estadoDigital == "ON"){
          message = new Paho.MQTT.Message("OFF");
          message.destinationName = '/' + usuario + '/salidaDigital'
          client.send(message);
        }
      };

      function enviarSalidaAnalogica(){
        var dato = document.getElementById("myRange").value;
        message = new Paho.MQTT.Message(dato);
        message.destinationName = '/' + usuario + '/salidaAnalogica'
        client.send(message);
      };
       
      // called when the client connects
      function onConnect() {
        // Once a connection has been made, make a subscription and send a message.
        console.log("onConnect");
        client.subscribe("#");
      }
        
      // called when the client loses its connection
      function onConnectionLost(responseObject) {
        if (responseObject.errorCode !== 0) {
          console.log("onConnectionLost:", responseObject.errorMessage);
          setTimeout(function() { client.connect() }, 5000);
        }
      }
        
      // called when a message arrives
      function onMessageArrived(message) {
        if (message.destinationName == '/' + usuario + '/' + 'temperatura') { //acá coloco el topic
            //document.getElementById("temperatura").textContent = message.payloadString  + " ºC";
            g.refresh(message.payloadString);
            temperaturas = parseFloat(message.payloadString);
        }
        if (message.destinationName == '/' + usuario + '/' + 'pulsador') { //acá coloco el topic
            //document.getElementById("pulsador").textContent = message.payloadString;
            if (message.payloadString == "presionado"){
              document.getElementById("imgPulsador").src = "presionado.png"
            }
            else if (message.payloadString == "NO presionado"){
              document.getElementById("imgPulsador").src = "nopresionado.png"
            }
         }
        if (message.destinationName == '/' + usuario + '/' + 'salidaDigital') { //acá coloco el topic
            //document.getElementById("salidaDigital").textContent = message.payloadString;
            estadoDigital = message.payloadString;

            if (estadoDigital == "OFF") {
              document.getElementById("led1").setAttribute("stop-color", "#110000");
            }
            else if (estadoDigital == "ON") {
              document.getElementById("led1").setAttribute("stop-color", "#ff0000");
            }
        }
        if (message.destinationName == '/' + usuario + '/' + 'salidaAnalogica') { //acá coloco el topic
            //document.getElementById("salidaAnalogica").textContent = message.payloadString;
            document.getElementById("led2").setAttribute("stop-color", "rgb(0, " + parseInt(message.payloadString/4) + ", 0)")
        }
      }

        function onFailure(invocationContext, errorCode, errorMessage) {
          var errDiv = document.getElementById("error");
          errDiv.textContent = "Could not connect to WebSocket server, most likely you're behind a firewall that doesn't allow outgoing connections to port 39627";
          errDiv.style.display = "block";
        }
        
        var clientId = "ws" + Math.random();
        // Create a client instance
        var client = new Paho.MQTT.Client("m13.cloudmqtt.com", 31948, clientId);
        
        // set callback handlers
        client.onConnectionLost = onConnectionLost;
        client.onMessageArrived = onMessageArrived;
        
        // connect the client
        client.connect({
          useSSL: true,
          userName: usuario,
          password: contrasena,
          onSuccess: onConnect,
          onFailure: onFailure
        });

        Highcharts.setOptions({
            global: {
                useUTC: false
            }
        });

        // Create the chart
        Highcharts.stockChart('container', {
            chart: {
                events: {
                    load: function () {

                        // set up the updating of the chart each second
                        var series = this.series[0];
                        setInterval(function () {
                            var x = (new Date()).getTime(), // current time
                                y =temperaturas;
                            series.addPoint([x, y]);
                        }, 1000);
                    }
                }
            },

            rangeSelector: {
                buttons: [{
                    count: 1,
                    type: 'minute',
                    text: '1M'
                }, {
                    count: 5,
                    type: 'minute',
                    text: '5M'
                }, {
                    type: 'all',
                    text: 'All'
                }],
                inputEnabled: false,
                selected: 0
            },

            title: {
                text: 'Temperatura ºC'
            },

            exporting: {
                enabled: false
            },

            series: [{
                name: 'ºC',
                data: (function () {
                    // generate an array of random data
                    var data = [],
                        time = (new Date()).getTime(),
                        i;

                    for (i = -300; i <= 0; i += 1) {
                        data.push([
                            time + i * 1000,
                            -1
                        ]);
                    }
                    return data;
                }())
            }]
        });

          
        
    </script>
  </body>
</html>

sábado, 12 de agosto de 2017

Tutorial #15 ESP8266 (Parte5) – Diseño en tu Dashboard MQTT usando CSS y JavaScript

Este es el quinto tutorial de IOT (internet de las cosas) usando MQTT en un ESP8266; en estos videos (Parte A y B) les muestro como agregarle diseño al dashboard (tablero) que vimos en el tutorial 13, para eso vamos a hacer uso de CSS y JavaScript.

Parte A:


Parte B:


tutorial15.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Tutorial 15</title>
    <script src='mqttws31.js' type='text/javascript'></script> 
    <!-- https://api.cloudmqtt.com/sso/js/mqttws31.js -->
    <script src="raphael-2.1.4.min.js"></script>
    <script src="justgage.js"></script>    
  </head>
  <style type="text/css">
    .a200x160px {
      width: 200px;
      height: 160px;
    }
    img {
      margin-left: 75px;
    }

    .switch {
      position: relative;
      display: inline-block;
      width: 120px;
      height: 68px;
    }

    .switch input {display:none;}

    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #ccc;
      -webkit-transition: .4s;
      transition: .4s;
    }

    .slider:before {
      position: absolute;
      content: "";
      height: 52px;
      width: 52px;
      left: 8px;
      bottom: 8px;
      background-color: white;
      -webkit-transition: .4s;
      transition: .4s;
    }

    input:checked + .slider {
      background-color: red;
    }

    input:focus + .slider {
      box-shadow: 0 0 1px #2196F3;
    }

    input:checked + .slider:before {
      -webkit-transform: translateX(52px);
      -ms-transform: translateX(52px);
      transform: translateX(52px);
    }

    .slider.round {
      border-radius: 68px;
    }

    .slider.round:before {
      border-radius: 50%;
    }

    input[type=range] {
      height: 26px;
      -webkit-appearance: none;
      margin: 10px 0;
      width: 120px;
    }
    input[type=range]:focus {
      outline: none;
    }
    input[type=range]::-webkit-slider-runnable-track {
      width: 100%;
      height: 14px;
      cursor: pointer;
      animate: 0.2s;
      box-shadow: 1px 1px 1px #50555C;
      background: #50555C;
      border-radius: 14px;
      border: 0px solid #000000;
    }
    input[type=range]::-webkit-slider-thumb {
      box-shadow: 0px 0px 0px #000000;
      border: 0px solid #000000;
      height: 20px;
      width: 40px;
      border-radius: 12px;
      background: green;
      cursor: pointer;
      -webkit-appearance: none;
      margin-top: -3px;
    }
    input[type=range]:focus::-webkit-slider-runnable-track {
      background: #50555C;
    }
   
    input[type=range]:focus::-ms-fill-lower {
      background: #50555C;
    }
    input[type=range]:focus::-ms-fill-upper {
      background: #50555C;
    }
  </style>
  <body>
      <div id="gauge" class="a200x160px"></div>
      <div>
        <img id="imgPulsador" src="nopresionado.png">
      </div>
      <div>
         <svg width="100" height="75" viewBox="0 0 640 480">
         <defs>
          <linearGradient id="svg_6" x1="0" y1="0" x2="1" y2="0">
           <stop stop-color="#bfbfbf" offset="0"/>
           <stop stop-color="#404040" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_11" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop id="led1" stop-color="#000000" stop-opacity="0.992188" offset="0"/>
           <stop stop-color="#820101" stop-opacity="0.988281" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_14" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop stop-color="#ffffff" stop-opacity="0.996094" offset="0"/>
           <stop stop-color="#d30606" stop-opacity="0.984375" offset="0.703125"/>
          </linearGradient>
         </defs>
         <g>
          <title>Layer 1</title>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" cx="320" cy="240" r="196.125" id="svg_3" fill-opacity="0.77" transform="rotate(90, 320, 240)"/>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" fill-opacity="0.64" cx="319.252837" cy="239.999045" r="160" id="svg_7"/>
          <circle fill="url(#svg_11)" stroke-width="17.5" stroke-linecap="round" cx="320.000535" cy="240.001698" r="150" id="svg_8"/>
          <ellipse fill="url(#svg_14)" stroke-width="17.5" stroke-linecap="round" cx="250.179609" cy="170.124194" rx="75.675959" ry="44.402987" id="svg_20" transform="rotate(-47.7626, 250.18, 170.125)"/>
         </g>
        </svg>
        <label class="switch">
          <input type="checkbox" onclick='OnOff2()'>
          <span class="slider round"></span>
        </label>
      </div>
      <div>
         <svg width="100" height="75" viewBox="0 0 640 480">
         <defs>
          <linearGradient id="svg_26" x1="0" y1="0" x2="1" y2="0">
           <stop stop-color="#bfbfbf" offset="0"/>
           <stop stop-color="#404040" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_211" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop id="led2" stop-color="rgb(0, 0, 0)" stop-opacity="0.992188" offset="0"/>
           <stop stop-color="#018201" stop-opacity="0.988281" offset="1"/>
          </linearGradient>
          <linearGradient id="svg_214" x1="0" y1="0" x2="1" y2="1" spreadMethod="pad">
           <stop stop-color="#ffffff" stop-opacity="0.996094" offset="0"/>
           <stop stop-color="#06d306" stop-opacity="0.984375" offset="0.703125"/>
          </linearGradient>
         </defs>
         <g>
          <title>Layer 1</title>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" cx="320" cy="240" r="196.125" id="svg_23" fill-opacity="0.77" transform="rotate(90, 320, 240)"/>
          <circle fill="url(#svg_6)" stroke-width="17.5" stroke-linecap="round" fill-opacity="0.64" cx="319.252837" cy="239.999045" r="160" id="svg_27"/>
          <circle fill="url(#svg_211)" stroke-width="17.5" stroke-linecap="round" cx="320.000535" cy="240.001698" r="150" id="svg_28"/>
          <ellipse fill="url(#svg_214)" stroke-width="17.5" stroke-linecap="round" cx="250.179609" cy="170.124194" rx="75.675959" ry="44.402987" id="svg_220" transform="rotate(-47.7626, 250.18, 170.125)"/>
         </g>
        </svg>
        <input type="range" id="myRange" min="0" max="1023"  onmouseup="enviarSalidaAnalogica()">
      </div>
    <script>      
      usuario = 'placa2';
      contrasena = '12345678';

      var g = new JustGage({
        id: "gauge",
        min: 0,
        max: 50,
        title: "Temperatura ºC"
      });

      estadoDigital = "OFF";

      function OnOff2(){
        if (estadoDigital == "OFF"){
          message = new Paho.MQTT.Message("ON");
          message.destinationName = '/' + usuario + '/salidaDigital'
          client.send(message);
        }
        else if (estadoDigital == "ON"){
          message = new Paho.MQTT.Message("OFF");
          message.destinationName = '/' + usuario + '/salidaDigital'
          client.send(message);
        }
      };

      function enviarSalidaAnalogica(){
        var dato = document.getElementById("myRange").value;
        message = new Paho.MQTT.Message(dato);
        message.destinationName = '/' + usuario + '/salidaAnalogica'
        client.send(message);
      };
       
      // called when the client connects
      function onConnect() {
        // Once a connection has been made, make a subscription and send a message.
        console.log("onConnect");
        client.subscribe("#");
      }
        
      // called when the client loses its connection
      function onConnectionLost(responseObject) {
        if (responseObject.errorCode !== 0) {
          console.log("onConnectionLost:", responseObject.errorMessage);
          setTimeout(function() { client.connect() }, 5000);
        }
      }
        
      // called when a message arrives
      function onMessageArrived(message) {
        if (message.destinationName == '/' + usuario + '/' + 'temperatura') { //acá coloco el topic
            //document.getElementById("temperatura").textContent = message.payloadString  + " ºC";
            g.refresh(message.payloadString);
        }
        if (message.destinationName == '/' + usuario + '/' + 'pulsador') { //acá coloco el topic
            //document.getElementById("pulsador").textContent = message.payloadString;
            if (message.payloadString == "presionado"){
              document.getElementById("imgPulsador").src = "presionado.png"
            }
            else if (message.payloadString == "NO presionado"){
              document.getElementById("imgPulsador").src = "nopresionado.png"
            }
         }
        if (message.destinationName == '/' + usuario + '/' + 'salidaDigital') { //acá coloco el topic
            //document.getElementById("salidaDigital").textContent = message.payloadString;
            estadoDigital = message.payloadString;

            if (estadoDigital == "OFF") {
              document.getElementById("led1").setAttribute("stop-color", "#110000");
            }
            else if (estadoDigital == "ON") {
              document.getElementById("led1").setAttribute("stop-color", "#ff0000");
            }
        }
        if (message.destinationName == '/' + usuario + '/' + 'salidaAnalogica') { //acá coloco el topic
            //document.getElementById("salidaAnalogica").textContent = message.payloadString;
            document.getElementById("led2").setAttribute("stop-color", "rgb(0, " + parseInt(message.payloadString/4) + ", 0)")
        }
      }

        function onFailure(invocationContext, errorCode, errorMessage) {
          var errDiv = document.getElementById("error");
          errDiv.textContent = "Could not connect to WebSocket server, most likely you're behind a firewall that doesn't allow outgoing connections to port 39627";
          errDiv.style.display = "block";
        }
        
        var clientId = "ws" + Math.random();
        // Create a client instance
        var client = new Paho.MQTT.Client("m13.cloudmqtt.com", 31948, clientId);
        
        // set callback handlers
        client.onConnectionLost = onConnectionLost;
        client.onMessageArrived = onMessageArrived;
        
        // connect the client
        client.connect({
          useSSL: true,
          userName: usuario,
          password: contrasena,
          onSuccess: onConnect,
          onFailure: onFailure
        });        
    </script>
  </body>
</html>

Enlaces externos:

http://justgage.com
https://www.flaticon.com/free-icon/one-finger-click-black-hand-symbol_56011
https://www.flaticon.com/free-icon/touch-of-one-finger-of-solid-black-hand-symbol_55421
http://www.downloadclipart.net/svg/18483-led-red-off-svg.svg
https://www.w3schools.com/howto/howto_css_switch.asp
http://www.cssportal.com/style-input-range/

sábado, 5 de agosto de 2017

Tutorial #14 ESP8266 (Parte4) – Login en tu Dashboard MQTT

Este es el cuarto tutorial de IOT usando MQTT en un ESP8266; es un complemento del número 13, en el que les mostré cómo hacer sus propios dashboards (tableros).  En este video muestro cómo hacer un login previo de exactamente el mismo ejemplo anterior. En el tutorial muestro como hacer la aplicación web usando PHP (además de HTML y JavaScript), tanto en un servidor local como en un servidor externo.



index.html:

<!DOCTYPE html>
<html >
<head>
  <meta charset="UTF-8">
  <title>Login - Tutorial 14</title>
</head>
<body>
  <form action="login.php" method="POST">
    <input type="text" name="user" placeholder="usuario">
    <input type="password" name="pass" placeholder="contraseña">
    <input type="submit" name="Enviar" >
  </form>
</body>
</body>
</html>

login.php:

<?php

$user = $_POST ['user'];
$pass = $_POST ['pass'];

require_once ('tutorial14A.html');
echo "      
  usuario = '$user';
  contrasena = '$pass';
";
require_once ('tutorial14B.html');

?>

tutorial14A.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Tutorial 14</title>
    <script src='mqttws31.js' type='text/javascript'></script> 
    <!-- https://api.cloudmqtt.com/sso/js/mqttws31.js -->    
  </head>
  <body>
      <div>
        <h2>Suscripciones:</h2>
      </div>
      <div>
        <a>Temperatura: </a>
        <a id ="temperatura">-</a>
      </div>
      <div>
        <a>Pulsador: </a>
        <a id ="pulsador">-</a>
      </div>
      <div>
        <a>Salida Digital: </a>
        <a id ="salidaDigital">-</a>
      </div>
      <div>
        <a>Salida Analógica: </a>
        <a id ="salidaAnalogica">-</a>
      </div>
      <div>
        <h2>Publicaciones:</h2>
      </div>
      <div>
        <a>Salida Digital: </a>
        <button type='button' onclick='OnOff("ON")'>ON</button>
        <button type='button' onclick='OnOff("OFF")'>OFF</button>
      </div>
      <div>
        <a>Salida Analógica: </a>
        <input type="range" id="myRange" min="0" max="1023"  onmouseup="enviarSalidaAnalogica()">
      </div>
    <script>

tutorial14B.html:


      function OnOff(dato){
        message = new Paho.MQTT.Message(dato);
        message.destinationName = '/' + usuario + '/salidaDigital'
        client.send(message);
      };

      function enviarSalidaAnalogica(){
        var dato = document.getElementById("myRange").value;
        message = new Paho.MQTT.Message(dato);
        message.destinationName = '/' + usuario + '/salidaAnalogica'
        client.send(message);
      };
       
      // called when the client connects
      function onConnect() {
        // Once a connection has been made, make a subscription and send a message.
        console.log("onConnect");
        client.subscribe("#");
      }
        
      // called when the client loses its connection
      function onConnectionLost(responseObject) {
        if (responseObject.errorCode !== 0) {
          console.log("onConnectionLost:", responseObject.errorMessage);
          setTimeout(function() { client.connect() }, 5000);
        }
      }
        
      // called when a message arrives
      function onMessageArrived(message) {
        if (message.destinationName == '/' + usuario + '/' + 'temperatura') { //acá coloco el topic
            document.getElementById("temperatura").textContent = message.payloadString  + " ºC";
        }
        if (message.destinationName == '/' + usuario + '/' + 'pulsador') { //acá coloco el topic
            document.getElementById("pulsador").textContent = message.payloadString;
        }
        if (message.destinationName == '/' + usuario + '/' + 'salidaDigital') { //acá coloco el topic
            document.getElementById("salidaDigital").textContent = message.payloadString;
        }
        if (message.destinationName == '/' + usuario + '/' + 'salidaAnalogica') { //acá coloco el topic
            document.getElementById("salidaAnalogica").textContent = message.payloadString;
        }
      }

        function onFailure(invocationContext, errorCode, errorMessage) {
          var errDiv = document.getElementById("error");
          errDiv.textContent = "Could not connect to WebSocket server, most likely you're behind a firewall that doesn't allow outgoing connections to port 39627";
          errDiv.style.display = "block";
        }
        
        var clientId = "ws" + Math.random();
        // Create a client instance
        var client = new Paho.MQTT.Client("m11.cloudmqtt.com", 30722, clientId);
        
        // set callback handlers
        client.onConnectionLost = onConnectionLost;
        client.onMessageArrived = onMessageArrived;
        
        // connect the client
        client.connect({
          useSSL: true,
          userName: usuario,
          password: contrasena,
          onSuccess: onConnect,
          onFailure: onFailure
        });        
    </script>
  </body>
</html>

domingo, 30 de julio de 2017

Tutorial #13 ESP8266 (Parte3) - Tus Propios Dashboards (Tableros) MQTT

En la tercera parte de los tutoriales de IOT usando MQTT en ESP8266, explico cómo hacer nuestros propios dashboards (tableros), valiéndonos de HTML y JavaScript; lo que nos permite controlar y monitorear nuestros dispositivos mediante una aplicación web, ya sea desde una PC, tablet, smartphone, etc. Si bien el ejemplo es muy sencillo y carece de diseño, es perfectamente funcional, ya que le idea del video es que se entiendan los conceptos y en futuros videos contemplaremos el diseño, la seguridad, etc.


tutorial13.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Tutorial 13</title>
    <script src='mqttws31.js' type='text/javascript'></script> 
    <!-- https://api.cloudmqtt.com/sso/js/mqttws31.js -->    
  </head>
  <body>
      <div>
        <h2>Suscripciones:</h2>
      </div>
      <div>
        <a>Temperatura: </a>
        <a id ="temperatura">-</a>
      </div>
      <div>
        <a>Pulsador: </a>
        <a id ="pulsador">-</a>
      </div>
      <div>
        <a>Salida Digital: </a>
        <a id ="salidaDigital">-</a>
      </div>
      <div>
        <a>Salida Analógica: </a>
        <a id ="salidaAnalogica">-</a>
      </div>
      <div>
        <h2>Publicaciones:</h2>
      </div>
      <div>
        <a>Salida Digital: </a>
        <button type='button' onclick='OnOff("ON")'>ON</button>
        <button type='button' onclick='OnOff("OFF")'>OFF</button>
      </div>
      <div>
        <a>Salida Analógica: </a>
        <input type="range" id="myRange" min="0" max="1023"  onmouseup="enviarSalidaAnalogica()">
      </div>
    <script>      
      usuario = 'placa1';
      contrasena = '12345678';

      function OnOff(dato){
        message = new Paho.MQTT.Message(dato);
        message.destinationName = '/' + usuario + '/salidaDigital'
        client.send(message);
      };

      function enviarSalidaAnalogica(){
        var dato = document.getElementById("myRange").value;
        message = new Paho.MQTT.Message(dato);
        message.destinationName = '/' + usuario + '/salidaAnalogica'
        client.send(message);
      };
       
      // called when the client connects
      function onConnect() {
        // Once a connection has been made, make a subscription and send a message.
        console.log("onConnect");
        client.subscribe("#");
      }
        
      // called when the client loses its connection
      function onConnectionLost(responseObject) {
        if (responseObject.errorCode !== 0) {
          console.log("onConnectionLost:", responseObject.errorMessage);
          setTimeout(function() { client.connect() }, 5000);
        }
      }
        
      // called when a message arrives
      function onMessageArrived(message) {
        if (message.destinationName == '/' + usuario + '/' + 'temperatura') { //acá coloco el topic
            document.getElementById("temperatura").textContent = message.payloadString  + " ºC";
        }
        if (message.destinationName == '/' + usuario + '/' + 'pulsador') { //acá coloco el topic
            document.getElementById("pulsador").textContent = message.payloadString;
        }
        if (message.destinationName == '/' + usuario + '/' + 'salidaDigital') { //acá coloco el topic
            document.getElementById("salidaDigital").textContent = message.payloadString;
        }
        if (message.destinationName == '/' + usuario + '/' + 'salidaAnalogica') { //acá coloco el topic
            document.getElementById("salidaAnalogica").textContent = message.payloadString;
        }
      }

        function onFailure(invocationContext, errorCode, errorMessage) {
          var errDiv = document.getElementById("error");
          errDiv.textContent = "Could not connect to WebSocket server, most likely you're behind a firewall that doesn't allow outgoing connections to port 39627";
          errDiv.style.display = "block";
        }
        
        var clientId = "ws" + Math.random();
        // Create a client instance
        var client = new Paho.MQTT.Client("m11.cloudmqtt.com", 30722, clientId);
        
        // set callback handlers
        client.onConnectionLost = onConnectionLost;
        client.onMessageArrived = onMessageArrived;
        
        // connect the client
        client.connect({
          useSSL: true,
          userName: usuario,
          password: contrasena,
          onSuccess: onConnect,
          onFailure: onFailure
        });        
    </script>
  </body>
</html>