Project tutorial
Logifox: The End of E-Waste Has Arrived

Logifox: The End of E-Waste Has Arrived © GPL3+

A low-power IoT platform for reverse logistics based on a smart pallet and a real-time monitoring app.

  • 6,639 views
  • 0 comments
  • 13 respects

Components and supplies

Abx00014 featured xjsqphgdlv
Arduino MKR Fox 1200
Microcontroller-based board acting as core of the prototype
×1
1434509556 android phone color
Android device
LG G3 D855 with Android 5.0
×1
13762 00
SparkFun IMU Breakout - MPU-9250
Accelerometer to generate events on new part recognition
×1
Load cell (3 kg)
Load cell to measure weight of parts
×1
HX711 load cell amplifier
Amplifier with ADC integrated to get the digital output of weight
×1
Elegoo Double-sided PCB
To solder connections on the prototype
×1
11026 02
Jumper wires (generic)
To solder connections on the double-sided PCBs
×20
3.7 V LiPo Battery
680 mAh LiPo battery
×1

Necessary tools and machines

09507 01
Soldering iron (generic)
AOYUE soldering station
Methacrylate sheet
Base of the prtotype
Dremel workstation
To make hollows on the surface of the methacrylate sheet
Pallet (miniature)
Upper-side of the load cell prototype
Screws
4x load cell and 4x double-sided PCB

Apps and online services

Ide web
Arduino IDE
For the development of Arduino codes for the MKR 1200 FOX board
Sigfox logo rgb j7ilnvhq6o
Sigfox
Sigfox technology and back-end connectivity
Logo firebase 8fxzjc8wki
Google Firebase
Database to receive Sigfox uplink messages
Apache Cordova
To develop a multiplatform app based on HTML5, CSS and JavaScript
JQuery Mobile
Plugin for Apache Cordova

About this project

Our names are Celia Garrido-Hidalgo and Luis Roda-Sánchez, Industrial Electronics and Automation engineers and currently students of the Master Degree in Industrial Engineering by the University of Castilla-La Mancha (Spain). Our project is called "Logifox" and is focused on reverse logistics using Sigfox.

Logifox in a Nutshell

Logifox is a low-power IoT device that contributes to circular economy by managing the reverse flow of reusable parts disassembled from products that are returned to supply chain by end-customers. It consists of a Sigfox-ready prototype attached to a pallet thought to be used in warehouses for real-time inventory tracking of parts. In this video we introduce the prototype:

Introduction of Logifox by Celia and Luis

The concept is simple: IoT for reverse logistics to minimize e-waste. Here's the architecture of the solution implemented:

Motivation: Reverse Logistics

According to the U.S.Environmental Protection Agency (EPA), more than 416, 000 mobile phones and 142, 000 personal computers are discarded every day. In fact, only the 16 % of these devices are actually recycled, reaching the amount of 49.8 million tons of worldwide e-waste expected to be generated by the end of this year.

Environmental monitoring of pollution and greenhouse gases is a great application for IoT but, what if we tackle the roots of the problem by reducing the amount of electronic waste worldwide? Not only could we promote Circular Economy to raise global awareness, but also provide end-customers with an active solution able to simplify the ordering of electronic components that could be reused. Well, here is where Logifox comes into play.

The Idea Behind Logifox

Logifox is a Sigfox device thought to be attached to pallets in smart warehouses to keep inventory levels of reusable parts updated. It includes a load cell to classify incoming parts disassembled from products such as computers, televisions of phones and, on the arrival of any new item, it updates inventory information on Sigfox backend.

Although Logifox is the core of the hardware prototype, the low-power wireless connectivity provided by Sigfox enables a sustainable IoT development. Besides, to track inventory levels and enable customers to access real-time information, we have developed a multiplatform application for SmartPhone, considering RAM memories, hard disks and graphic cards as categories of reusable parts:

The next picture shows how a typical supply chain would cooperate, highlighting the reverse flow of products from many organizations to an intermediate warehouse, where many smart pallets based on Logifox track inventory levels and update information on the app using the global Sigfox network infrastructure and cloud.

The main benefits of Logifox are:

  • Reverse Logistics enabler: it facilitates the management of a reverse flow of reusable parts by providing automatically inventory information associated to each pallet. By promoting the reuse of electronic parts we can avoid the manufacturing of extra components (so that the existing ones can be used until their end of life) and minimize the impact on the environment of disposed components, whose recycling procedure can also be harmful.
  • Simplicity of use: it encourages customers to get information of second-hand products and parts that are perfectly reusable, through the use of a straightforward interface updated in real-time through the Sigfox backend.
  • Smart connectivity: its IoT connectivity provided by Sigfox technology enables a full cooperation with Smart Logistics platforms based on Industry-4.0 solutions.
  • Power awareness: not only it promotes recycling and reusing strategies, but demands a reduced power itself.
  • Few resources: Logifox is a lightweight device that exploits the hardware resources used. A tiny IoT board, the MKR FOX 1200, sending at most 140 messages a day is more than enough to update inventory information of a specific pallet, not requiring further wireless technologies or infrastructures.

How Does It Work?

Logifox is composed of a load cell, accelerometer and Sigfox radio module (integrated in the MKR FOX 1200 board). Since it communicates with the Sigfox backend to transmit inventory data, the mobile app acts as user interface for end-customers aiming to order reusable parts contained on pallets. The app is based on Apache Cordova framework and JQuery Mobile plugin and connects to Sigfox backend to gather inventory information.

The inteface of the app is simple, a main menu to select the category of reusable part to track and three secondary screens (as an example) to get useful information from each category such as pallet identifier, number of items on it or warehouse ID, among others. For this, Firebase has been used as an intermediary database to store Sigfox messages from the pallets in a JSON file and forward these messages to the app in real-time.

The following sections describe the hardware developments and software programming required to implement the prototype of Logifox, in addition to some screenshots of the app developed working with Firebase and the Sigfox backend.

1. CREATE IT: #HW

This section focuses on the hardware and the setup of the tools and materials used to develop Logifox.

#HW1: Setting Up the Pallet

In the first place, we have acquired tiny pallets to be used as weighing platform for inventory management. The following picture shows the ones required for the first step: drill, load cell, screws, methacrylate sheet and double-sided PCB.

Then, we have hollowed the pallet using the drill and introduced the screws as shown in the following picture. Here you can find a useful guide on how to setup a load cell with the HX711 amplifier. Any amplified could have been used, but this one is typically distributed with the load cell itself, since it includes an analog to digital converter and facilitates the programming developments.

A brief checklist to ensure that everything is OK with the load cell:

  • The arrow should point to the right direction (down).
  • The thinnest screws should be used to screw the load cell to the upper surface and the thicker to fix the usion with the base of the prototype.
  • A small separation is required between the load cell and the two surrounding surfaces, in any other case the sensor would find difficulty in weighing correctly parts because it would receive stress in different points.

#HW2: First Prototype

In this second step we used the Dremel to hollow the surface of the methacrylate sheet and screw the platforms.

Then, all sensors with no pre-soldered connections were setup (see the following picture of the accelerometer), and a first prototype of Logifox was achieved, using a normal breadboard in order ro test its operation.

*Important: do not forget to connect the 868 MHz antenna before using Sigfox radio, since it could damage the device (check the official documenation here for more information).

#HW3: Final Design

Once the prototype is deployed and everything works (see the #SW sections before continuing with this step), let's move it to a more robust design!

For this, we need one more time the soldering iron to solder the Arduino MKR 1200 FOX board to the double-sided PCB (our recommendation is to solder just the required pins, because in any other case it will be very difficult for you to remove the connections without damaging the pins). The same happens with the accelerometer and HX711 board.

In this case the soldered pins are: Digital2, Digital3, SDA, SCL, Vcc and GND.

The initial and final results of the connections (done with jumpers on the bottom side of the PCB) are in the following picture:

Eventually, two pins were screwed to the battery pins in order to source it with an external voltage. The battery used is a 3V7 LiPo of 660 mAh. For the selection of the battery, the answers of the Arduino forum were quite useful and (we can confirm) that everything works as expected:

Once followed all the steps, the hardware setup of Logifox is done, now let's change to software and programming (more time-demanding).

2. MAKE IT WORK: #SW

This section focuses on the software and the setup of the tools and platforms used to develop the functionality of Logifox. Since we have used many platforms combined to achieve the end-to-end connectivity, please, follow the steps in the same order as described.

#SW1: Arduino Libraries Setup

In the project Fox Advisor, we explained some months ago how to include Arduino libraries (from zero). A brief description is included in this project:

We can find the MKR FOX 1200 libraries directly in the sketch menu of Arduino IDE. In case they're not present, we can include them using the libraries manager.

In this case, apart from the MKR library, we'll need the following:

Although the HX711 and MPU9250 boards used are not the official ones from SparkFun, these guides are equally useful by the time of setting up the libraries, documentation and connections: "HX711" "MPU9250".

In the first place, to program the load cell a previous calibration sketch is required. One calibrated, we will obtain a calibration factor (in this case 671) which should be introduced into the final programming code. This sketch is available online and at the end of this project (referenced to the original author with some small modifications).

Regarding the accelerometer, we measure acceleration and compare it with reference values to ensure that the Smart Pallet doesn't check inventory while it's being transported by a truck, for instance. Thus, weight is only measured by the load cell when the three acceleration data say that the pallet is not moving. This is a double-check security purpose. See the programming code for further information about the way in which we check motion.

#SW2: Apache Cordova

Apache Cordova is an open source development framework. It enables developers to build mobile apps using HTML, CSS and JavaScript (JS). Cordova can be used across several platforms easily and it provides access to native device APIs. In this case, we have chosen an Android device, but with other platforms the procedure is analogous. We recommend this guide to create a new Cordova project. Open your terminal and perform the following steps:

cordova create DemoProjectcom.evothings.demoapp DemoApp

cd DemoProject

cordova platform add android

cordova build android

Finally, your app folder should show something like this:

After that, you have to add some packages using the command android sdk on your terminal. Once the Android SDK Manager is open, you must install your android API (depending on your android version), the android tools package and several extra packages (found in Extras folder) in order to use Firebase Realtime Database. These packages are:

  • AndroidSupport Repository
  • GoogleRepository
  • GoogleUSB Driver

As you can see in the next figure:

We will extend the way to use this framework to develop our app.

#SW3: Firebase

We selected Firebase Realtime Database to store data from Sigfox backend. It's a NoSQL cloud-hosted database where data is stored as JSON and synchronized in realtime to every connected client.

First, we have to create a Firebase account. When we log in with our Google account we can see something like this, where we have to click on add new project:

We are sorry but the web automatically translated the content to spanish, so we couldn't include screenshots in english. Anyway, we will comment all structions and you will be able to follow the steps.

Now, we have to add a project name and accept the conditions as far as you agree.

Once we have accepted, our project is created and we can click on database.

Then, select start with testing mode (see screenshot). In this mode, the rules of our database are set up for prototyping porpuses but for a final development an authentication mode has to be selected.

This should be the aspect of your database at this point:

Now, we should add Firebase to our app. In this case, as mentioned before, we are developing an Android app. First, we should install Firebase in our app using npm install --save firebase command. Later, we have to select Android app configuration.

After that, another page shows some steps to install Firebase Realtime Database. The first thing we have to do is to find our build.gradle file placed in app directory and look for the applicationId name in our app since we have to write it in the textbox.

Now, a google-services.json has been created and you have to place it in your app directory.

It's time to add Firebase SDK to our project. For this, we have to open the build.gradle file located in the project path and copy the first text in the specified piece of code. The second and third texts should also be added to build.gradle file located in app level.

Finally, Firebase waits for the application connection. We should open a terminal and go to the root directory of our project. Now, we should type cordova run to build the application. After that, a successful message should appear and our Android app is already connected to our realtime database.

#SW4: Sigfox Backend

Regarding the Sigfox backend, first of all it is necessary to register the device to start using it. These steps are explained in short in the following lines, being the complete explanation part of a previous Hackster project of ours: Fox Advisor.

Let's start by creating a new account and activating the Sigfox device. For this, click and select a provider (Arduino) and your country. The next step is to introduce the ID and PAC codes. You'll find them in the Serial console of Arduino IDE, by executing the FirstConfiguration.ino example of the <SigFox.h> library.

Finally, if you don't have an account, you'll be able to create it in this step so that you registered device is associated with your user account.

Once we log in we have access to the Sigfox dashboard, where we'll click on device and, then, device type. Then, on the left-hand menu click 'callbacks' and create a 'custom callback'. The following pictures summarize the process:

In this case, the configuration used for the callback to PUT data into Firebase is the following:

  • Type: DATA, UPLINK
  • Channel: URL
  • Use HTTP method: PUT
  • Content type: application/json
  • BODY:
{
"ram":
 {
   "ID": "{device}",
   "payload": "{data}"
 }
}

#SW5: App

The app has been developed with Apache Cordova framework and jQuery mobile plugin has been used for the design of the interface. When we create a Cordova project, in the www folder we can see our index.html document. It's used to define the content and appearance of our app. The functionality is added by the index.js file located in the www/js folder. Besides, we can include images to our app using the img folder and define styles that will be used in the project in index.css.

Here you can see very useful guides to configure Firebase in the app. The code below shows the packages added and the initialization of Firebase in index.html file to manage our database with our app (where secret keys have been removed).

<script src="https://www.gstatic.com/firebasejs/4.0.0/firebase.js"></script>
       <script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-app.js"></script>
       <script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-auth.js"></script>
       <script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-database.js"></script>
       <script>
         // Initialize Firebase
         // TODO: Replace with your project's customized code snippet
         var config = {
           apiKey: "XXXXXXXXXXXXXX....XXXXXXXXXXX",
           authDomain: "XXXXXXXXXXX.firebaseio.com",
           databaseURL: "https://XXXXXXXXXXX.firebaseio.com",
           storageBucket: "",
           messagingSenderId: "XXXXXXXXXXXXX",
         };
         firebase.initializeApp(config);
         var ref = firebase.database();
       </script>

As can be observed, four packages have been added specifying their respective versions. Config variable is used to place apiKey, messagingSenderId (found in configuration/cloud messaging) and other parameters shown in database.

The code developed for our app can be observed in the programming code included in this project and the final design of the interface can be seen in the following figures:

In this project we developed the complete functionality of RAM memory category whereas hard disk and graphic card categories have been programmed with default values.

Final Result and Demo

The result is the prototype shown in the following video, which communicates with the Sigfox backend, Firebase and Cordova app to monitor inventory levels of reusable parts. In this demonstration, the parts used are RAM memories disassembled from laptops that had different reasons of failure.

Testing Logifox with the app developed using RAM memories as reusable parts

That's all! From now on, reducing e-waste is in your hands!

Code

JS file of the Cordova projectJavaScript
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* Programming code developed by:
 * Celia Garrido-Hidalgo
 * Luis Roda-Snchez
 */

/*
 * HTTP connection between Sigfox backend and Firebase Realtime Database (Google).
 * Source: https://firebase.google.com/
 */

document.addEventListener('deviceready', function onDeviceReady() {
    var db = firebase.database();
    var ref = db.ref("itemsReport");
    var databaseInfo;

    // Attach an asynchronous callback to read the data at our reference
    ref.on("value", function(snapshot) {
        databaseInfo = snapshot.val();
        decode(databaseInfo);
    }, function(errorObject) {
        alert("The read failed: " + errorObject.code);
    });
});

function decode(data) {
    var dataPayload = data.ram.payload;
    var dataID = data.ram.ID;
    var dataSector;
    var dataWarehouse;
    callback(function segment() {
            dataItems = dataPayload.charCodeAt(1) - 48; // To decode the hex value from the string received from Sigfox
            dataSector = dataPayload.charCodeAt(3) - 48;
            dataWarehouse = dataPayload.charCodeAt(5) - 48;
        },
        function refresh() {
            document.getElementById("idItems").innerHTML = dataItems; // Linking application elements with variables
            document.getElementById("idPallet").innerHTML = dataID;
            document.getElementById("idSector").innerHTML = dataSector;
            document.getElementById("idWarehouse").innerHTML = dataWarehouse;
        });
}

function callback(first, second) {
    first();
    second();
}
HTML file of the Cordova projectHTML
<!DOCTYPE html>
<!--
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
-->
<!--
    Programming code developed by:
    Celia Garrido-Hidalgo
    Luis Roda-Snchez
 -->

<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="msapplication-tap-highlight" content="no" />
        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <title>LogiFox</title>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />

        <link rel="stylesheet" type="text/css" href="css/index.css" />
        
        <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
        <script type="text/javascript" src="cordova.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
        
        <script src="https://www.gstatic.com/firebasejs/4.0.0/firebase.js"></script>
        <script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-app.js"></script>
        <script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-auth.js"></script>
        <script src="https://www.gstatic.com/firebasejs/4.0.0/firebase-database.js"></script>
        <script>
          // Initialize Firebase
          // TODO: Replace with your project's customized code snippet
          var config = {
            apiKey: "AAAA9YcEPyw:APA91bGNRJbXEN6kZ69dwTvnNopInCRE0wRYCvsEV4aowQHU8oU6EW-TBOeykpVlOkOZzk6i0dmd47hW0XdUwj0LW2hMwEt3MCwmQn-TgnJFhXsOt1wOp-TvzXdHtE_Q3oldrIkcjEOvZrltXf0rhxyo_CVr7T4_DA",
            authDomain: "logifox-ba2b8.firebaseio.com",
            databaseURL: "https://logifox-ba2b8.firebaseio.com",
            storageBucket: "",
            messagingSenderId: "1054532189996",
          };

          firebase.initializeApp(config);
          var ref = firebase.database();
        </script>

       <style type="text/css">
            html, body 
            {
                height: auto;
                margin: 0px;
            }
            .container 
            {
                height: auto;
                background: #ffffff;
            }
        </style>

        <style>

            p.inventory
            {
                line-height: 10%;
                color: rgb(186, 37, 37);
                font-size: 50px;
                text-align:center;
                margin-top:25px;
                margin-bottom:25px;
            }
            p.normal 
            {
                font-weight:bold;
                line-height: 70%;
                color: rgb(0, 0, 0);
                font-size: 20px;
                margin-top:18px;
                margin-bottom:18px;
                margin-left:10px;
            }
            p.dato
            {
                color: rgb(156, 37, 37);
                font-size: 20px;
                margin-top:18px;
                margin-bottom:18px;
            }

            p.title 
            {
                font-weight:normal;
                margin:10px;
                overflow:visible;
                padding:0px;
                text-align:center;
                color: rgb(21, 127, 87);
                font-size: 16px;
            }
            img
            {
                margin:0px;
                padding:0px;
                width: 100%;
            }
        </style>

    </head>
    <body>
        <div class="container" data-role="page" id="pageone">
            <div data-role="header">
                <p class = "title"> <b>LOGIFOX</b> </p>
            </div>
            
            <div role="main" class="ui-content">
                <img src="../www/img/main.png" style="width: 100%" alt="">
                <ul data-role="listview" data-ajax="false" data-inset="true" data-theme="a">
                    <li> <a href="#harddisk">HARD DISK<img src="../www/img/harddisklogo.png" style="width: 100%" alt=""></a> </li>
                    <li> <a href="#rammemory">RAM MEMORY<img src="../www/img/ramlogo.png" style="width: 100%" alt=""></a></li>
                    <li> <a href="#graphiccard">GRAPHIC CARD<img src="../www/img/graphiccardlogo.png" style="width: 100%" alt=""></a></li>
                </ul>
                </select>
            </div>
        </div>

        <div class="container" data-role="page" id="information">
            <div data-role="header">
                <p class = "title"> <b>GENERAL</b> </p>
            </div>
            
            <div style="margin:20px;" data-role="main" class="ui-content">
                
                <img src="../www/img/about.png" style="width: 100%" alt="">
            </div>
        </div>

        <div class="container" data-role="page" id="harddisk">
            <div data-role="header">
                <p class = "title"><b>HARD DISK</b></p>
                <a href="#pageone" class="ui-btn-left ui-btn-inline ui-btn ui-icon-home ui-btn-icon-left">Home</a>
                <a href="#sector" class="ui-btn-right ui-btn-inline ui-btn ui-icon-back ui-btn-icon-right">Back</a>
            </div>

            <div data-role="main" class="ui-content">
                <img src="../www/img/harddisk1.png" style="width: 100%" alt="">   
                <div data-role="controlgroup">                    
                    <p class = "inventory"><b>0</b></p>
                </div>
                <img src="../www/img/2.png" style="width: 100%" alt="">
                <form>
                  <table style="width: 100%">
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Pallet</p></td>
                            <td align="left" width="10%"><p class = "dato"><b>1F3035</b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Sector</p></td>
                            <td align="left" width="10%"><p class = "dato"><b>1</b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Warehouse</p></td>
                            <td align="left" width="10%"><p class = "dato"><b>7</b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                    </table>
                </form>
            </div>
        </div>

        <div class="container" data-role="page" id="rammemory">
            <div data-role="header">
                <p class = "title"><b>RAM MEMORY</b></p>
                <a href="#pageone" class="ui-btn-left ui-btn-inline ui-btn ui-icon-home ui-btn-icon-left">Home</a>
                <a href="#sector" class="ui-btn-right ui-btn-inline ui-btn ui-icon-back ui-btn-icon-right">Back</a>
            </div>

            <div data-role="main" class="ui-content">
                <img src="../www/img/ram1.png" style="width: 100%" alt="">
                <div data-role="controlgroup">                    
                    <p class = "inventory"><b><span id="idItems"></span></b></p>
                </div>
                <img src="../www/img/2.png" style="width: 100%" alt="">
                <form>
                  <table style="width: 100%">
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Pallet</p></td>
                            <td align="left" width="10%"><p class = "dato"><b><span id="idPallet"></span></b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Sector</p></td>
                            <td align="left" width="10%"><p class = "dato"><b><span id="idSector"></span></b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Warehouse</p></td>
                            <td align="left" width="10%"><p class = "dato"><b><span id="idWarehouse"></span></b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                    </table>
                </form>
                
            </div>
        </div>

        <div class="container" data-role="page" id="graphiccard">
            <div data-role="header">
                <p class = "title"><b>GRAPHIC CARD</b></p>
                <a href="#pageone" class="ui-btn-left ui-btn-inline ui-btn ui-icon-home ui-btn-icon-left">Home</a>
                <a href="#sector" class="ui-btn-right ui-btn-inline ui-btn ui-icon-back ui-btn-icon-right">Back</a>
            </div>

            <div data-role="main" class="ui-content">
                <img src="../www/img/graphiccard1.png" style="width: 100%" alt="">
                <div data-role="controlgroup">
                    <p class = "inventory"><b>0</b></p>
                </div>
                <img src="../www/img/2.png" style="width: 100%" alt="">
                <form>
                  <table style="width: 100%">
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Pallet</p></td>
                            <td align="left" width="10%"><p class = "dato"><b>1D2035</b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Sector</p></td>
                            <td align="left" width="10%"><p class = "dato"><b>2</b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                        <tr style= "line-height:5%">
                            <td align="left" width="60%"><p class = "normal">Warehouse</p></td>
                            <td align="left" width="10%"><p class = "dato"><b>7</b></p></td>
                            <td align="right" width="30%"><p class = "normal"></p></td>
                        </tr>
                    </table>
                </form>
                
            </div>
        </div>
            </div>
        </div>
    </body>
</html>
CSS file of the Cordova projectCSS
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
* {
    -webkit-tap-highlight-color: rgb(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
}

body {
    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
    background-color:#E4E4E4;
    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
    background-image:-webkit-gradient(
        linear,
        left top,
        left bottom,
        color-stop(0, #A7A7A7),
        color-stop(0.51, #E4E4E4)
    );
    background-attachment:fixed;
    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
    font-size:15px;
    height:100%;
    margin:0px;
    padding:0px;
    width:100%;
}

/* Portrait layout (default) */
.app {
    background:url(../img/foto.png) no-repeat center top; /* 170px x 200px */
    position:absolute;             /* position in the center of the screen */
    left:50%;
    top:50%;
    height:50px;                   /* text area height */
    width:225px;                   /* text area width */
    text-align:center;
    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */
    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */
                                   /* offset horizontal: half of text area width */
}
.ui-content {
    margin: 0; padding: 0;
}

/* Landscape layout (with min-width) */
@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
    .app {
        background-position:left center;
        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */
        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */
                                      /* offset horizontal: half of image width and text area width */
    }
}

.event {
    border-radius:4px;
    -webkit-border-radius:4px;
    color:#FFFFFF;
    font-size:12px;
    margin:0px 30px;
    padding:2px 0px;
}

.event.listening {
    background-color:#333333;
    display:block;
}

.event.received {
    background-color:#4B946A;
    display:none;
}

@keyframes fade {
    from { opacity: 1.0; }
    50% { opacity: 0.4; }
    to { opacity: 1.0; }
}
 
@-webkit-keyframes fade {
    from { opacity: 1.0; }
    50% { opacity: 0.4; }
    to { opacity: 1.0; }
}
 
.blink {
    animation:fade 3000ms infinite;
    -webkit-animation:fade 3000ms infinite;
}
Logifox code (Arduino MKR FOX 1200)Arduino
/*
  Based on :
  [1]: Calibration sketch of HX711 library - https://circuits4you.com/2016/11/25/hx711-arduino-load-cell/
  [2]: Official documentation of MKR FOX 1200 - https://www.arduino.cc/en/Main.ArduinoBoardMKRFox1200
  [3]: SparkFun documentation of the MPU 9250 - https://www.sparkfun.com/products/13762

  Programmed by Luis Roda-Sanchez and Celia Garrido-Hidalgo on 13/05/2017
*/

#include <SigFox.h>
#include "HX711.h"
#include <Wire.h>
#include <MPU9250.h>

#define AHRS false         // Set to false for basic data read in the accelerometer
#define DOUT 3
#define CLK 2

HX711 scale(DOUT, CLK);

float accelX, accelY, accelZ, absMovX, absMovY, absMovZ, motion;

MPU9250 IMU;

float calibration_factor = 671; // Obtained from the calibration routine

bool motionDetected = false;

bool hardDisk = false; // Variables to store the type of products received by the pallet:
bool networkCard = false;
bool graphicCard = false;
bool ramMemory = true;

int typeOfPart [4] = {hardDisk, networkCard, graphicCard, ramMemory};
int minWeight [4] = {642, 55, 220, 8}; // To define the threshold for new part detection

int numberOfParts;
int typePosition;
int weight;

int previousWeight = 0;
bool firstTime = true, auxPlus = false, auxLess = false;

typedef struct __attribute__ ((packed)) sigfox_message { // Structure to store information to be sent to sigfox-backend
  uint8_t numberItems = 0; // Initialization
  uint8_t sector = 3; // Default
  uint8_t warehouseID = 7; // Default
} SigfoxMessage;

SigfoxMessage msg; // Stub for message which will be sent


void setup() {
  Serial.begin(38400);
  Wire.begin();
  IMU.initMPU9250(); // Initialization of the accelerometer
  scale.set_scale(); // Reference: [1]
  scale.tare(); // Reset the scale to 0

  for (typePosition = 0; typePosition < 4; typePosition++) { // Finding the kind of parts stored by the pallet
    if (typeOfPart[typePosition] == true) {
      break;
    }
  }

  long zero_factor = scale.read_average(); // Getting a baseline reading

  scale.set_scale(calibration_factor); // Adjust to this calibration factor
  scale.tare();

  if (!SigFox.begin()) {
    // Something is wrong
  }

  SigFox.end(); // Send module to standby until we need to send a message
  SigFox.debug(); // For more information check the Forum http://forum.arduino.cc/index.php?topic=478950.0;nowap
  delay(20);
}


void loop() {
  IMU.readAccelData(IMU.accelCount);  // // Read the x/y/z adc values
  IMU.getAres(); // Conversion to gs.

  accelX = (float)IMU.accelCount[0] * IMU.aRes * 1000;
  accelY = (float)IMU.accelCount[1] * IMU.aRes * 1000;
  accelZ = (float)IMU.accelCount[2] * IMU.aRes * 1000;

  absMovX = abs(accelX); // To facilitate further comparison
  absMovY = abs(accelY);
  absMovZ = abs(accelZ);

  motion = absMovX + absMovY; // We sum the accelerations to gain more accuracy

  Serial.print(absMovX);
  Serial.print("  ");
  Serial.print(absMovY);
  Serial.print("  ");
  Serial.println(absMovZ);
  if (motion < 130 && absMovZ > 970 && absMovZ < 1030) { // Only in case the pallet is not being transported will it update inventory (manually-adusted thresholds)
    Serial.println("Entro");

    weight = (int)scale.get_units(10);

    if (firstTime == true && weight != 0) { // New part on the pallet
      delay(2000); // Wait ultil weight is stable
      if ((int)scale.get_units(10) > (minWeight[typePosition] - minWeight[typePosition] * 0.2)) { // Identifies as new part
        Serial.println("First item inside, sending to Sigfox back-end...");

        firstTime = false;
        previousWeight = (int)scale.get_units(10);
        numberOfParts = 1;

        Serial.println("Number of items inside updated, sending to Sigfox back-end...:");
        Serial.println(numberOfParts);
        msg.numberItems = numberOfParts;
        SigFox.begin(); // Wait at least 30ms after first configuration (100ms before)
        delay(100);
        SigFox.status();
        delay(1);
        SigFox.beginPacket(); // Sending packet via Sigfox
        SigFox.write((uint8_t*)&msg, 3);
        SigFox.endPacket(); // We finish the packet
        SigFox.end();
      }
    }
    else if (firstTime == false && weight != 0) {
      delay(2000); // Wait ultil weight is stable
      if (((int)scale.get_units(10) - previousWeight) > (minWeight[typePosition] - minWeight[typePosition] * 0.2)) { // To increment the number of parts
        numberOfParts ++;
        auxPlus = true;
      }
      else if (((int)scale.get_units(10) - previousWeight) < -(minWeight[typePosition] - minWeight[typePosition] * 0.2)) { // To decrement the number of parts
        numberOfParts--;
        auxLess = true;
      }

      if (auxPlus == true || auxLess == true) {
        auxLess = false; // Reset
        auxPlus = false;
        Serial.println("Number of items updated: "); // New part
        Serial.println(numberOfParts);
        msg.numberItems = numberOfParts;
        SigFox.begin(); // Wait at least 30ms after first configuration (100ms before)
        delay(100);
        SigFox.status();
        delay(1);
        SigFox.beginPacket(); // Sending packet via Sigfox
        SigFox.write((uint8_t*)&msg, 3);
        SigFox.endPacket(); // We finish the packet
        SigFox.end();
      }
      previousWeight = (int)scale.get_units(10); // Store previousWeight for further comparison
    }
  }
}

Schematics

Logifox schematics
Schematics of Logifox using a MKR FOX 1200, 5kg load cell and MPU 9250 accelerometer (previous to soldering connections)
Fritzing 6rc3dwamov

Comments

Similar projects you might like

Carfox: A Device to Find Them All

Project tutorial by Luis Roda Sánchez

  • 7,457 views
  • 2 comments
  • 28 respects

Fox Advisor

Project tutorial by Celia Garrido Hidalgo

  • 3,166 views
  • 2 comments
  • 12 respects

Sigfox kWh Meter

Project tutorial by jassak

  • 6,287 views
  • 8 comments
  • 15 respects

Smart Bird Feeder

Project showcase by Team ESIEE-Amiens Students

  • 3,771 views
  • 9 comments
  • 15 respects

IoTrix (Smart Advertisement LED Board)

Project tutorial by Ravi Parmar

  • 2,279 views
  • 0 comments
  • 20 respects
Add projectSign up / Login