Difference between revisions of "Weigh Scale MQTT"

From Lantronix Wiki!
Jump to navigation Jump to search
 
Line 82: Line 82:
 
         except Exception:
 
         except Exception:
 
             pass
 
             pass
 +
 +
=== Sending Data to Google Analytics ===
 +
Since the Google Analytics Measurement Protocol uses standard HTTP requests to send data from devices other than web browsers, the ga.send method is easily implemented using the Python '''''urllib''''' and '''''urllib2''''' modules.
 +
 +
class gaConnect:
 +
    def __init__(self, tracking, mac):
 +
        self.tracking = tracking
 +
        self.mac = mac
 +
 +
    def send(self, data):
 +
        values = { 'v' : '1',
 +
                    'tid' : self.tracking,
 +
                    'cid' : self.mac,
 +
                    't' : 'event',
 +
                    'ec' : 'scale',
 +
                    'ea' : 'weight',
 +
                    'el' : data }
 +
 +
        res = urllib2.urlopen(urllib2.Request("http://www.google-analytics.com/collect", urllib.urlencode(values)))
 +
 +
=== Sending Data to 2lemetry Cloud Platform using MQTT ===
 +
The sampled data is sent to the 2lemetry cloud platform using the MQTT protocol. MQTT client is implemented using the imported '''Mosquitto''' package and its functions are used for communicating with 2lemetry via MQTT.
 +
 +
class connection2lemetry:
 +
    def __init__(self, dev):
 +
        self.client = mosquitto.Mosquitto('things/'+dev.mac)
 +
        self.client.username_pw_set("USERNAME", password="PASSWORD")
 +
        #self.client.connect("q.m2m.io")
 +
        #self.client.loop()
 +
        self.id = dev.mac
 +
 +
    def send(self, value):
 +
        self.client.connect("q.m2m.io")
 +
        self.client.loop()
 +
        self.client.publish('30025f33189599eed42d868bce9670dd/things/'+self.id,'{"report":{"test":{"weight":"'+value+'"}}}',1)
 +
        self.client.loop()
 +
        self.client.disconnect()
 +
 +
    def disconnect(self):
 +
        self.client.disconnect()
 +
 +
=== Module Import and Initialization ===
 +
The following section of the code imports the required modules and checks for the installation of the '''tornado''' (Web Server) and '''mosquitto''' (MQTT client) modules.
 +
 +
import logging
 +
logging.basicConfig(level=logging.WARNING, filename='ew2014debug.log')
 +
import time
 +
import serial
 +
import commands
 +
import os
 +
from multiprocessing import Process, Value
 +
import threading
 +
import urllib2
 +
import urllib
 +
 +
try:
 +
    import tornado.ioloop
 +
    import tornado.web
 +
except Exception, ex:
 +
    logging.exception('Make sure Tornado and backports are correctly installed')
 +
 +
try:
 +
    import mosquitto
 +
    supportMqtt = True
 +
except:
 +
    supportMqtt = False
 +
    logging.exception('Make sure Mosquitto module is installed')
 +
 +
=== Program Initialization ===
 +
Program initialization reads the device serial number (MAC address), initializes the connection to the Google Analytics and 2lemetry cloud platform with the appropriate credentials (replaced here with obscured credentials). The tornado web server is started and the program enters a loop where it processes the serial data from the weighing scale and processes it for transmission to the browser (locally served up web pages), Google Analytics and 2lemetry cloud platform.
 +
 +
if __name__ == '__main__':
 +
    # time.sleep(30)
 +
    #os.system('route add default gw 172.19.0.1 eth0')
 +
    os.system('/etc/init.d/S19-ltrx-network-common')
 +
    dev = pwDevice()
 +
    print dev.mac
 +
    weight = Value('d',0.0)
 +
    ga = gaConnect("UA-YYYY", dev.mac)
 +
    c2l = None
 +
    if supportMqtt:
 +
        try:
 +
            c2l = connection2lemetry(dev)
 +
        except Exception, ex:
 +
            logging.exception('Failed to connect to 2lemetry')
 +
 +
    p = Process(target=startServer, args=(8888,weight,))
 +
    p.start()
 +
    time.sleep(1)
 +
    s = ser349klx('/dev/ttyS2', weight, c2l, ga)
 +
    p2 = Process(target=s.getData)
 +
    p2.start()
 +
    p.join()
 +
    p2.join()
 +
 +
=== Web Server Initialization and Handlers ===
 +
The web server is initialized with the handlers for the supporting URLs and starts processing HTTP requests. The implementation of the various handlers is also shown below.
 +
 +
class MainHandler(tornado.web.RequestHandler):
 +
    def get(self):
 +
        self.render("ew2014demo.html")
 +
 +
class weightHandler(tornado.web.RequestHandler):
 +
    def initialize(self, weight):
 +
        self.weight = weight
 +
 +
    def get(self):
 +
        self.write("{:.2f}".format(self.weight.value))
 +
 +
class cellHandler(tornado.web.RequestHandler):
 +
    def initialize(self, weight):
 +
        self.weight = weight
 +
 +
    def post(self):
 +
        num = self.get_argument('number','')
 +
 +
        print num
 +
        if num:
 +
            os.system('ctest sms-send ' + num + ' ' + str(self.weight.value))
 +
        print num
 +
 +
        self.render("ew2014demo.html")
 +
 +
def startServer(port,weight):
 +
    settings = {
 +
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
 +
    }
 +
    application = tornado.web.Application([
 +
        (r'/', MainHandler),
 +
        (r'/weight', weightHandler, dict(weight=weight,)),
 +
        (r'/submit_cell', cellHandler, dict(weight=weight,)),
 +
        (r'/static/(.*)', tornado.web.StaticFileHandler, dict(path=settings['static_path'])),
 +
    ])
 +
    application.listen(port)
 +
    tornado.ioloop.IOLoop.instance().start()
 +
    print 'Started web server'

Latest revision as of 06:41, 20 November 2014

Introduction

This demonstration sample shows how easy it is to add local processing to the IoT network edge and communicate with cloud based IoT and Analytics platforms. Here we see the Lantronix PremierWave family of Intelligent Gateways connect to an end device via a serial port like RS-232/485, or Ethernet, intelligently extract useful data, and send it to 2lemetry Cloud Platform and Google Analytics. Standard and scalable M2M/IoT transport protocols such as MQTT and HTTP are easy to integrate within a custom application while relying on the secure remote access and robust device management features of the rugged Cellular M2M Gateways such as Lantronix PremierWave XC HSPA+.

Requirements

  • Python module PySerial - built-in module supported in Python for Lantronix products
  • Tornado webserver package
  • Digital scale with RS232 serial port (Homedics 349KLX)
    Any other serial device could be used and its protocol implemented in Python instead
  • Internet Connection via cellular or Ethernet

Setup

Weigh scale demo.png


The demonstration setup consists of the digital scale with RS232 connected to one of the RS232 ports on PremierWave XC HSPA+. The Python script performs the following actions:

  • Values from digital scale are read over the RS232 port
  • Send SMS to user’s cell phone with the weight read from scale
  • Digital scale readings are posted to 2lemetry cloud via MQTT protocol
  • Digital scale readings are posted to Google Analytics via HTTP
  • Local access to the web server via the browser provides scale read-out

Technical Details

Initialize the Serial Ports via PySerial

The program uses the PySerial module that is built-in the Python support on Lantronix devices. For more details on the module refer to the ]]//Lantronix_Python_Programmers_Guide | Programmer's Guide]].

class ser349klx:
# setup the serial port. Pass the device as '/dev/ttyS1' or '/dev/ttyS2' for
# serial port 1 and 2 (respectively) in PremierWave EN or XC HSPA+
def __init__(self, device, weight, c21, ga):
    while True:
    try:
        serstat = True
        ser = serial.Serial(device,2400, interCharTimeout=0.2, timeout=1)
    except Exception:
    serstat = False
    if serstat:
        break

    self.ser = ser
    self.weight = weight
    self.c21 = c21
    self.ga = ga

Read Scale data

The scale constantly sends the current weight via the RS232 port, with each value separate by a carriage return

def receive_line(self):
    buffer = 

    while True:
    buffer = buffer + self.ser.read(self.ser.inWaiting())
    if '\r' in buffer:
        lines = buffer.split('\r')
    return lines[-2]

Processing the new weight readings and taking actions

# This runs a continuous loop listening for lines coming from the
# serial port and processing them.
def getData(self):
    count = 0
    prev = 0.0

    #print self.ser.interCharTimeout
    while True:
        time.sleep(0.1)
        try:
            val = self.receive_line()
            weight.value=float(val[-5:])*0.166
            if (prev == weight.value):
                count += 1
                if (count == 10) and (str(prev) != '0.0'):
                    self.ga.send("{:.2f}".format(prev))
                    if supportMqtt:
                        self.c2l.send("{:.2f}".format(prev))
            else:
                count = 0
                prev = weight.value
        except Exception:
            pass

Sending Data to Google Analytics

Since the Google Analytics Measurement Protocol uses standard HTTP requests to send data from devices other than web browsers, the ga.send method is easily implemented using the Python urllib and urllib2 modules.

class gaConnect:
    def __init__(self, tracking, mac):
        self.tracking = tracking
        self.mac = mac
		
    def send(self, data):
        values = { 'v' : '1',
                   'tid' : self.tracking,
                   'cid' : self.mac,
                   't' : 'event',
                   'ec' : 'scale',
                   'ea' : 'weight',
                   'el' : data }
					
        res = urllib2.urlopen(urllib2.Request("http://www.google-analytics.com/collect", urllib.urlencode(values)))

Sending Data to 2lemetry Cloud Platform using MQTT

The sampled data is sent to the 2lemetry cloud platform using the MQTT protocol. MQTT client is implemented using the imported Mosquitto package and its functions are used for communicating with 2lemetry via MQTT.

class connection2lemetry:
    def __init__(self, dev):
        self.client = mosquitto.Mosquitto('things/'+dev.mac)
        self.client.username_pw_set("USERNAME", password="PASSWORD")
        #self.client.connect("q.m2m.io")
        #self.client.loop()
        self.id = dev.mac
	
    def send(self, value):
        self.client.connect("q.m2m.io")
        self.client.loop()
        self.client.publish('30025f33189599eed42d868bce9670dd/things/'+self.id,'{"report":{"test":{"weight":"'+value+'"}}}',1)
        self.client.loop()
        self.client.disconnect()

    def disconnect(self):
        self.client.disconnect()

Module Import and Initialization

The following section of the code imports the required modules and checks for the installation of the tornado (Web Server) and mosquitto (MQTT client) modules.

import logging
logging.basicConfig(level=logging.WARNING, filename='ew2014debug.log')
import time
import serial
import commands
import os
from multiprocessing import Process, Value
import threading
import urllib2
import urllib

try:
    import tornado.ioloop
    import tornado.web
except Exception, ex:
    logging.exception('Make sure Tornado and backports are correctly installed')

try:
    import mosquitto
    supportMqtt = True
except:
    supportMqtt = False
    logging.exception('Make sure Mosquitto module is installed')

Program Initialization

Program initialization reads the device serial number (MAC address), initializes the connection to the Google Analytics and 2lemetry cloud platform with the appropriate credentials (replaced here with obscured credentials). The tornado web server is started and the program enters a loop where it processes the serial data from the weighing scale and processes it for transmission to the browser (locally served up web pages), Google Analytics and 2lemetry cloud platform.

if __name__ == '__main__':
    #	time.sleep(30)
    #os.system('route add default gw 172.19.0.1 eth0')
    os.system('/etc/init.d/S19-ltrx-network-common')
    dev = pwDevice()
    print dev.mac
    weight = Value('d',0.0)
    ga = gaConnect("UA-YYYY", dev.mac)
    c2l = None
    if supportMqtt:
        try:
            c2l = connection2lemetry(dev)
        except Exception, ex:
            logging.exception('Failed to connect to 2lemetry')

    p = Process(target=startServer, args=(8888,weight,))
    p.start()
    time.sleep(1)
    s = ser349klx('/dev/ttyS2', weight, c2l, ga)
    p2 = Process(target=s.getData)
    p2.start()
    p.join()
    p2.join()

Web Server Initialization and Handlers

The web server is initialized with the handlers for the supporting URLs and starts processing HTTP requests. The implementation of the various handlers is also shown below.

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("ew2014demo.html")
	
class weightHandler(tornado.web.RequestHandler):
    def initialize(self, weight):
        self.weight = weight
	
    def get(self):
        self.write("{:.2f}".format(self.weight.value))
	
class cellHandler(tornado.web.RequestHandler):
    def initialize(self, weight):
        self.weight = weight
	
    def post(self):
        num = self.get_argument('number',)
	
        print num
        if num:
            os.system('ctest sms-send ' + num + ' ' + str(self.weight.value))
        print num
	
        self.render("ew2014demo.html")
def startServer(port,weight):		
    settings = {
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
    }
    application = tornado.web.Application([
        (r'/', MainHandler),
        (r'/weight', weightHandler, dict(weight=weight,)),
        (r'/submit_cell', cellHandler, dict(weight=weight,)),
        (r'/static/(.*)', tornado.web.StaticFileHandler, dict(path=settings['static_path'])),
    ])
    application.listen(port)
    tornado.ioloop.IOLoop.instance().start()
    print 'Started web server'