Skip to content

15. Interface and application programming

Individual assignment :

  • write an application that interfaces a user with an input &/or output device that you made

Group assignment :

  • compare as many tool options as possible

Individual assignment

This week I upgraded last week’s work. I added an RFID reader. When you scan a correct card, it welcomes you, otherwise not allowed

As a reminder, I use MQTT to do communication (like home automation).

MQTT links the interfaces and enables communication between them.

link

Wiring ESP32 + RFID

link

At the moment, when you scan a card or a bagde, you see the green light OK or red not OK. The goal here is to create an interface on a screen to see the change of authorisations (Welcome, Not authorised)

Download :

video before interface

Code for ESP 32
#include <WiFi.h>
#include <PubSubClient.h>
#include <SPI.h>
#include <MFRC522.h>

#define BUF_LEN 128

#define SS_PIN  34  // ESP32 pin GIOP5 
#define RST_PIN 40 // ESP32 pin GIOP27 

MFRC522 rfid(SS_PIN, RST_PIN);

const char* wifi_ssid = "WiFi-2.4-F8D8";
const char* wifi_password = "Y11PuvsFc72U";
const char* mqtt_server = "192.168.1.20";

WiFiClient espClient;
PubSubClient client(espClient);

int count_sleep = 0;

char mqtt_buffer[BUF_LEN];


void setup() {
  Serial.begin(115200);
  SPI.begin(); // init SPI bus
  rfid.PCD_Init(); // init MFRC522
  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  Serial.print("Connecting to WiFi..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println("");
  Serial.println(WiFi.localIP());
  client.setServer(mqtt_server, 1883);
  client.connect("esp32");
  Serial.println("Tap an RFID/NFC tag on the RFID-RC522 reader");
}


void loop() {
  char* ptr_buffer;
  if (rfid.PICC_IsNewCardPresent()) { // new tag is available
    if (rfid.PICC_ReadCardSerial()) { // NUID has been readed
      ptr_buffer = mqtt_buffer;
      for (int i = 0; i < rfid.uid.size; i++) {
        sprintf(ptr_buffer, "%02X", rfid.uid.uidByte[i]);
        ptr_buffer += 2;
      }
      *ptr_buffer = '\0'; // null terminator

      Serial.print("RFID: ");
      Serial.println(mqtt_buffer);
      client.publish("RFID", mqtt_buffer);

      rfid.PICC_HaltA(); // halt PICC
      rfid.PCD_StopCrypto1(); // stop encryption on PCD
    }
  }

  delay(1);
  count_sleep++;
  if (count_sleep == 50) {
    client.publish("esp32", "still connected");
     count_sleep = 0;
  }
}
Code for SAMD
#define BUF_LEN 64

int red_pin= 17;
int green_pin = 19;
int blue_pin = 18;

char read_buffer[BUF_LEN];
int n_buffer = 0;

void setup() {
  pinMode(red_pin, OUTPUT);
  pinMode(green_pin, OUTPUT);
  pinMode(blue_pin, OUTPUT);
  SerialUSB.begin(115200);
}


void parse_buffer() {
  int red_value = 0;
  int green_value = 0;
  int blue_value = 0;

  SerialUSB.println("buffer:");
  SerialUSB.println(read_buffer);
  if (sscanf(read_buffer, "[%d,%d,%d]", &red_value, &green_value, &blue_value) == 3) {
    RGB_color(red_value, green_value, blue_value);
  }
}

void loop() {
  if (SerialUSB.available()) {
    char c = SerialUSB.read();

    if (c == '\n') {
      read_buffer[n_buffer] = '\0'; // null terminator
      parse_buffer();
      n_buffer = 0;
    } else {
      read_buffer[n_buffer] = c;
      n_buffer++;
    }
  }
}

void RGB_color(int red_value, int green_value, int blue_value) {
  analogWrite(red_pin, red_value);
  analogWrite(green_pin, green_value);
  analogWrite(blue_pin, blue_value);
}

Interface Python

Code Python
import paho.mqtt.client as mqtt
import tkinter as tk
import time
import serial



mqtt_broker = "192.168.1.20"
btn = None

accepted_uid = ["8DE7D21E", "11E4D21E"]
ser_port = None

  # Message if ok or not ok
def on_message(client, userdata, message):
    global btn, accepted_uid,framebg

    if message.topic == "RFID":
        uid = message.payload.decode("utf-8")
        print(f'Received:\n  topic: {message.topic}, message: {uid}')
        if uid in accepted_uid:
            btn["text"] = "welcome"
            ser_port.write(b"[0,255,0]\n")
        else:
            btn["text"] = "unknown!"
            ser_port.write(b"[255,0,0]\n")
        time.sleep(1)
        btn["text"] = "<scan UID>"
        ser_port.write(b"[0,0,0]\n")


def main():
    global btn, ser_port, framebg, framebtn,f
    # setup window and button
    window = tk.Tk()
    window.geometry('300x230')
    window.title('Access Terminal')
    framebg="grey"
    framebtn="yellow"

    frame = tk.Frame(master=window, borderwidth=100, bg=framebg)

    frame.pack(side=tk.TOP)
    btn = tk.Label(master=frame, text="<scan UID>", bg=framebtn)
    btn.pack()


    # configure serial for samd + LED RGB
    print("Opening serial...")
    ser_port = serial.Serial("/dev/ttyACM0", 115200)
    print("done!")

    # setup MQTT
    client = mqtt.Client("my_pc")
    client.connect(mqtt_broker)
    client.on_message = on_message
    client.subscribe("RFID")

    # launch the app
    client.loop_start()
    window.mainloop()

    # stop the app
    ser_port.close()
    client.loop_stop()


if __name__ == '__main__':
    main()

video with interface

Group assignment

Group Link

Some programming languages

HTML et CSS

These are 2 complementary languages. They represent the basis of web development. HTML structures the web page. It allows to constitute its skeleton. It is on this basis that graphic and visual elements can be integrated from the CSS language, then position them in relation to each other.

** Advantages **

  • HTML has the advantage of being universal, and independent of any operating system.
  • It works on the basis of a distributed structure, i.e. external links are perfectly integrated. This makes it possible to modify an element without modifying the page where it is located.
  • Finally, HTML allows the integration of both local and remote elements, via the connection to a server.

** Disadvantages **

As a universal and simplified language, HTML can be limited in terms of page formatting. If you want to store your data locally, it is also not totally suitable. Moreover, the storage can quickly become cumbersome, depending on the number of pages of your website.

JavaScript

JavaScript is an interpreted programming language. It has the particularity of being activated on the client side. This means that when the user opens a web page, the browser activates the code to display the page.

JavaScript allows to integrate scripts between the HTML elements of the page, generally to add an animation or a visual effect. It is a useful language to improve the user experience, because it allows to add interactivity without slowing down the page.

** Advantages **

The main advantage of JavaScript is its security. Indeed, if your browser can retrieve a script in an HTML page, there is no risk that it accesses your files.

** Disadvantages **

As a language interpreted by browsers, JavaScript can be interpreted in different ways, from one browser to another. Some browsers, too old, do not follow the evolution of the language and may not be able to display the scripts.

PHP

PHP is a scripting language that, unlike JavaScript, is executed on the server side. It is closely related to HTML, with PHP tags embedded in the HTML code. For the client, it is impossible to see if PHP has been used.

The main role of PHP is to develop a good communication between the web page and the server. In this sense, PHP guarantees the good stability of web pages.

** Advantages **

The main advantages of PHP are :

  • Its great flexibility,
  • Its compatibility with many databases,
  • Its compatibility with most operating systems.

** Disadvantages **

PHP can have the disadvantage of generating random URLs, which it is necessary to rewrite in order not to see your pages penalized by search engine robots.

C#, C ou C++

The C language in all its forms is one of the oldest programming languages. It was developed in the 1970s to program systems. Its evolutions C# and C++ are extremely stable languages.

** Advantages **

These languages are recommended for beginners who want to learn programming, because they adapt to the evolution of new languages.

The C language has served as the basis for many other languages.

** Disadvantages **

The verification offered can be limited and C languages sometimes need additional tools to detect.

Python

Python has many advantages: it is fast, light, easy to install, and compatible with most operating systems. On the other hand, it is not adapted to the development of artificial intelligence for mobile applications.

my contribution

This week I was able to improve some “programs” that are quite useful in the fablab.

2 HTML programs with input form and calculation 1 HTML + Javascript for more complex calculations

You can use them directly here or download directly on github

Speed calculation for CNC

Link to application : link

SCREENSHOT

link

code html
<div>
<tr>
<td><center><h2><FONT face="Verdana" >Calculation of the parameters of the Mekanika CNC</h2></center></td>
</tr>
</table>
</div>


<p align="center"><img src="sheets.jpg" alt="Vitesse de coupe - VC" width=50%/></p>

<table border=0 width=100% >
<tr height=50><td colspan=2></td></tr>
<tr>
<td width=50%>
<p align=right>
    <B>VC : <input type="number" id="VC"> &nbsp; &nbsp; m/min</B>
</p>
</td>
<td >
<p align=left>
    <B>&nbsp; &nbsp;&nbsp; &nbsp;D : <input type="number" id="D"> mm</B>
</p>
</td>
</tr>
<tr>
<td>
<p align=right>
    <B>FZ : <input type="number" id="FZ"> mm/tooth</B>
</p>
</td>
<td>
<div class="ligne">
    <B>&nbsp; &nbsp;&nbsp; &nbsp;Z : <input type="number" id="Z"> nb tooth</B>
</div>
</td>
</tr>
<tr>
<td colspan=2>
<div class="ligne">
    <p align=center><button type="button" id="calcul">Calculate</button></p>
</td>
</tr>
</table>


<table border=0 width=100%>
<tr height=30><td colspan=2></td></tr>
<tr>
<td width=50%>
    <p align=right><font color=red><B>n max : <output type="number" id="n" ></B></font></p>
<td>    
    <p align=left><font color=red><B>tr/min</B></font></p>
</td>
</tr>
<tr>
<td>
    <p align=right><font color=red><B>Vf max : &nbsp;&nbsp;<output type="number" id="Vf"> </B></font></p>
</td>
<td>
    <p align=left><font color=red><B>mm/min </B></font></p>
</td>   
</tr>
<tr>
<td>
    <p align=right><font color=red><B>Vf max : &nbsp;&nbsp;<output type="number" id="Vfsec"> </B></font></p>
</td>
<td>
    <p align=left><font color=red><B>mm/sec </B></font></p>
</td>   
</tr>
</div>



</table>

<center>

<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.
</center>


<script>
document.getElementById('calcul').onclick = function () {
    VC = document.getElementById('VC').value;
    D = document.getElementById('D').value;
    n = (Math.round((1000 * parseFloat(VC)) / (3.14 * parseFloat(D))));
    document.getElementById('n').value = n;
    v5 = document.getElementById('n').value;
    FZ = document.getElementById('FZ').value;
    Z = document.getElementById('Z').value;
    Vf = (Math.round((Math.round(v5)* parseFloat(FZ)* parseFloat(Z))));
    document.getElementById('Vf').value = Vf;
    Vfsec = (Math.round(Vf / 60));
    document.getElementById('Vfsec').value = Vfsec;
    };
</script>

Calculation of filament length.

Link to application : link

SCREENSHOT

link

code html
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">


<head>
<title>Length of filaments</title>
<meta name="description" content="Correspondence between spool weight and filament length for 3D printer" />
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
</head>
<body>



<h2 style="text-align: justify;">Weight / length converter for wire spools</h2>
<p style="text-align: justify;">This conversion tool allows you to know the length of the filament in relation to a given mass, and vice versa.</p>
<p style="text-align: justify;">Select the material from the drop-down list.</p>
<p style="text-align: justify;">If the density does not match your material, you can change it if necessary.</p>
<form>
<table border="0">
<tbody>
<tr>
<td>
<p>Material :</p>
</td>
<td><select id="matiere" name="matiere" size="1" onchange="putdensite();"> <option value="PLA">PLA</option> <option value="ABS">ABS</option> <option value="PVA">PVA</option> <option value="PET">PET</option> <option value="HIPS">HIPS</option> <option value="Flexible">Flexible</option> <option value="PC">PC</option> <option value="Nylon">Nylon</option><option value="LayWoo">LayWoo</option> </select></td>
<td>
<p>Diameter :</p>
</td>
<td><select id="diametre" name="diametre" size="1" onchange="putdensite();"> <option value="1.75">1.75mm</option> <option value="2.85">2.85mm</option> <option value="3">3mm</option> </select></td>
<td>density (g/cm<sup>3</sup>)<input id="densite" onkeyup="calculdens();" type="text" name="densite" value="1.25" /></td>
</tr>
</tbody>
</table>
<br />Enter a length of yarn in cm or a mass in grams. The data is calculated automatically.<br /> length (m) : <input id="longueur" onkeyup="calculpoids();" type="text" name="longueur" /> weight (g) : <input id="poids" onkeyup="calcullongueur();" type="text" name="poids" />
<script type="text/javascript">// <![CDATA[
var dPLA = 1.25;
var dABS = 1.01;
var dPET = 1.26;
var dHIPS = 0.98;
var dFlexible = 1.14;
var dPVA = 1.29;
var dPC = 1.21;
var dNylon = 1.14;
var dLayWoo = 1.06;
function putdensite(){
var index = document.getElementById("matiere").value;
var co = "d"+index;
document.getElementById('densite').value = eval(co);
document.getElementById('longueur').value = 0;
}
function calcullongueur(){
document.getElementById('longueur').value = 
(document.getElementById('poids').value / 
((Math.PI *document.getElementById('diametre').value / 20*document.getElementById('diametre').value / 20) * 
document.getElementById('densite').value) / 100) .toFixed(1);
}
function calculpoids(){
document.getElementById('poids').value = 
((Math.PI *(document.getElementById('diametre').value / 20*document.getElementById('diametre').value / 20) *
document.getElementById('longueur').value) * 100 * 
document.getElementById('densite').value). toFixed(0);
}
function calculdens(){
if(document.getElementById('poids').value != 0)
document.getElementById('poids').value = ((Math.PI *(document.getElementById('diametre').value / 20*document.getElementById('diametre').value / 20)*document.getElementById('longueur').value)*document.getElementById('densite').value).toFixed(2);
else if (document.getElementById('longueur').value != 0)
document.getElementById('longueur').value = (document.getElementById('poids').value/((Math.PI *document.getElementById('diametre').value / 20*document.getElementById('diametre').value / 20) *document.getElementById('densite').value)).toFixed(2);
}
function putdensite_2(){
var index = document.getElementById("matiere_2").value;
var co = "d"+index;
document.getElementById('densite_2').value = eval(co);
document.getElementById('longueur_2').value =0;
}
function calcullongueur_2(){
var massefil = eval(document.getElementById('massetotale_2').value -
document.getElementById('bobine_2').value);
document.getElementById('longueur_2').innerHTML = (massefil / 
((Math.PI * document.getElementById('diametre_2').value / 20 * 
document.getElementById('diametre_2').value / 20) * 
document.getElementById('densite_2').value) / 100) .toFixed(1);
if (document.getElementById('longueur_2').innerHTML < 0){
document.getElementById('longueur_2').innerHTML = 0;
}
}
// ]]></script>
</form><form></form><form>
<h2>How much filament is left on the spool?</h2>
</form><form></form><form>You need 12 meters for your next print, your spool has started and you don't know if you will have enough filament?</form><form>Select the material and the diameter. Weigh your spool and the program will show you the number of meters left.</form><form></form><form>You can customise the density of the material and the mass of your spool alone.</form><form></form><form>
<table border="0">
<tbody>
<tr>
<td>
<p>Material :</p>
</td>
<td><select id="matiere_2" name="matiere_2" size="1" onchange="putdensite_2(); calcullongueur_2();"> <option value="PLA">PLA</option> <option value="ABS">ABS</option> <option value="PVA">PVA</option> <option value="PET">PET</option> <option value="HIPS">HIPS</option> <option value="Flexible">Flexible</option> <option value="PC">PC</option> <option value="Nylon">Nylon</option><option value="LayWoo">LayWoo</option></select></td>
<td>
<p>Diameter :</p>
</td>
<td><select id="diametre_2" name="diametre_2" size="1" onchange="putdensite_2(); calcullongueur_2();"> <option value="1.75">1.75mm</option> <option value="2.85">2.85mm</option> <option value="3">3mm</option> </select></td>
</tr>
</tbody>
<tbody>
<tr>
<td>Density (g/cm<sup>3</sup>) :</td>
<td><input id="densite_2" onkeyup="calcullongueur_2();" type="text" name="densite_2" value="1.25" /></td>
</tr>
<tr>
<td>
<p>Mass of the empty spool alone (g) :</p>
</td>
<td><input id="bobine_2" onkeyup="calcullongueur_2();" type="text" name="bobine_2" value="245" /></td>
<td>
<p>Spool with wire (g):</p>
</td>
<td><input id="massetotale_2" onkeyup="calcullongueur_2();" type="text" name="massetotale_2" /></td>
</tr>
</tbody>
</table>
<p style="display: inline;">Lenght (m):</p>
<p id="longueur_2" style="display: inline; color: red;"> </p>
</form>
<p style="text-align: justify;"> </p>

</html>

Cost calculation of a 3D part

Link to application : link

SCREENSHOT

link

code html
<!-- XML Header -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">

<title>3D Printing Cost Calculator</title>

   <!--############ META TAGS #############-->
   <script src="cost_calc.js" type="text/javascript"></script>

</head>

<body id="body">



<!------------------------------ BEGIN CALCULATOR ------------------------------>

<div id="container">

   <div id="pageHeader">
      <h1><span>Cost of a 3D print</span></h1>
   </div>

  <div id="calculator">

    <form>
      <table >
        <tbody><tr>
          <td id="leftcol"><b><a class="tooltip" title="Weight of the project including raft and stand ...">
          <span title="">Weight : </span></a></b></td>
          <td id="rightcol"><input id="object weight" value="50" size="6" type="text"></td>
      <td><b> &nbsp; gr</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Estimated printing time">
          <span title="">Printing time :</span></a></b></td>
          <td id="rightcol"><input id="printing time" value="5" size="6" type="text"></td>
          <td><b> &nbsp; hours</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Cost per 1 kilowatt hour">
          <span title="">Electricity Tariff :</span></a></b></td>
          <td id="rightcol"><input id="electric tariff" value="0.0568" size="6" type="text"></td>
          <td><b> &nbsp; &#128;/kWh</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Average power consumption in watts">
          <span title="">Printer power :</span></a></b></td>
          <td id="rightcol"><input id="printer power" value="50" size="6" type="text"></td>
          <td><b> &nbsp; Watts</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Cost of filament including delivery">
          <span title="">Cost of filament :</span></a></b></td>
          <td id="rightcol"><input id="filament cost" value="34.19" size="6" type="text"></td>
          <td><b> &nbsp; &#128;/kg</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Total cost of the printer including delivery">
          <span title="">Cost of the printer :</span></a></b></td>
          <td id="rightcol"><input id="printer purchase" value="1576" size="6" type="text"></td>
          <td><b> &nbsp; &#128;</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="How long you will keep the printer">
          <span title="">Printer depreciation :</span></a></b></td>
          <td id="rightcol"><input id="printer life" value="3" size="6" type="text"></td>
          <td><b> &nbsp; year(s)</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Average printer usage per day">
          <span title="">Daily use :</span></a></b></td>
          <td id="rightcol"><input id="printer use" value="2" size="6" type="text"></td>
          <td><b> &nbsp; hours</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Estimated % maintenance costs for the printer">
          <span title="">Maintenance costs :</span></a></b></td>
        <td id="rightcol"><input id="repair rate" value="10" size="6" type="text"></td>
        <td><b> &nbsp; %</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Other costs: modelling, consumables, etc.">
          <span title="">Other costs :</span></a></b></td>
          <td id="rightcol"><input id="other costs" value="0.1" size="6" type="text"></td>
          <td><b> &nbsp; &#128;</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Print failure rate">
          <span title="">Failure rate :</span></a></b></td>
          <td id="rightcol"><input id="failure rate" value="10" size="6" type="text"></td>
          <td><b> &nbsp; %</b></td>
        </tr>
        <tr>
          <td id="leftcol"><b><a class="tooltip" title="Total cost for an object">
          <span title="">Total cost :</span></a></b></td>
          <td id="rightcol"><input id="total cost" class="total" value="4.65" size="6" readonly="readonly" type="text"></td>
          <td><b> &nbsp; &#128;</b></td>
        </tr>
        <tr>
        <td id="leftcol">&nbsp;<br><input id="calculate" onclick="displayTotal();" value="Calculate" type="button"></td>
        </tr>
        <tr>
        <td id="leftcol">&nbsp;<br><input id="reset defaults" onclick="resetDefaults();displayValues();" value="Reset" type="button"></td>
        </tr>
      </tbody></table>
    </form>
    <br><br>

    <script type="text/javascript">
      afterPageLoad();
    </script>

  </div>

</div>



<!------------------------------- END CALCULATOR ------------------------------->


</html>
code javascript
const COOKIE_DAYS = 365;

var floatObjectWeight = "";
var floatPrintingTime = "";
var floatElectricTariff = "";
var floatPrinterPower = "";
var floatFilamentCost = "";
var floatPrinterPurchase = "";
var floatPrinterLife = "";
var floatPrinterUse = "";
var floatRepairRate = "";
var floatOtherCosts = "";
var floatFailureRate = "";

//=============================================================
// setCookie - set a cookie on the host device
//=============================================================
function setCookie(strCookieName, intCookieValue, intExpireDays)
{
  var dateExDate;

  // Set cookie with value and expiry date
  dateExDate = new Date();
  dateExDate.setDate(dateExDate.getDate() + intExpireDays);
  document.cookie=strCookieName + "=" + escape(intCookieValue) +
  ((intExpireDays == null) ? "" : ";expires=" + dateExDate.toGMTString());
}


//=============================================================
// getCookie - read a cookie from the host device
//=============================================================
function getCookie(strCookieName)
{
  var intCookieStart;
  var intCookieEnd;
  var strCookieValue;

  // Assume no cookie until found
  strCookieValue = "";

  // Extract cookie value if it exists
  if (document.cookie.length > 0)
  {
    intCookieStart = document.cookie.indexOf(strCookieName + "=");
    if (intCookieStart != -1)
    {
      intCookieStart = intCookieStart + strCookieName.length + 1;
      intCookieEnd = document.cookie.indexOf(";", intCookieStart);
      if (intCookieEnd == -1)
      {
        intCookieEnd = document.cookie.length;
      }
      strCookieValue = unescape(document.cookie.substring(intCookieStart, intCookieEnd));
    }
  }

  // Return cookie value
  return strCookieValue;
}


//=============================================================
// calcEnergy - returns electricity costs for object
//=============================================================
function calcEnergy()
{
  var floatEnergy;
  var floatKW;
  var floatPoundsHour;

  // Calculations based on spreadsheet
  floatKW = floatPrinterPower / 1000.0;
  floatPoundsHour = floatKW * floatElectricTariff;
  floatEnergy = floatPoundsHour * floatPrintingTime;

  // Return energy cost
  return floatEnergy;
}


//=============================================================
// calcFilament - returns filament costs for object
//=============================================================
function calcFilament()
{
  var floatFilament;

  // Calculations based on spreadsheet
  floatFilament = floatFilamentCost / 1000.0 * floatObjectWeight;

  // Return floatFilament cost
  return floatFilament;
}


//=============================================================
// calcLifetime - returns lifetime hours for object
//=============================================================
function calcLifetime()
{
  var floatLifetime;

  // Calculations based on spreadsheet
  floatLifetime = 365.0 * floatPrinterLife * floatPrinterUse;

  // Return depreciation cost
  return floatLifetime;
}


//=============================================================
// calcDepreciation - returns depreciation costs for object
//=============================================================
function calcDepreciation()
{
  var floatDepreciation;
  var floatLifetime;
  var floatDeprHr;

  // Calculations based on spreadsheet
  floatLifetime = calcLifetime();
  floatDeprHr = floatPrinterPurchase / floatLifetime;
  floatDepreciation = floatDeprHr * floatPrintingTime;

  // Return depreciation cost
  return floatDepreciation;
}


//=============================================================
// calcRepairs - returns repair costs for object
//=============================================================
function calcRepairs()
{
  var floatRepairs;
  var floatRepairsHr;

  // Calculations based on spreadsheet
  floatRepairsHr = (floatPrinterPurchase / 100.0 * floatRepairRate) / calcLifetime();
  floatRepairs = floatRepairsHr * floatPrintingTime;

  // Return repairs cost
  return floatRepairs;
}


//=============================================================
// calcOther - returns other costs for object
//=============================================================
function calcOther()
{
  var floatOther;

  // Calculations based on spreadsheet
  floatOther = floatOtherCosts;

  // Return other cost
  return floatOther;
}


//=============================================================
// calcTotalNotFailures - returns cost besides floatFailures for object
//=============================================================
function calcTotalNotFailures()
{
  var floatTotalNotFailures;

  // Calculate total costs before failures
  floatTotalNotFailures = calcEnergy() +
                          calcFilament() +
                          calcDepreciation() +
                          calcRepairs() +
                          calcOther();

  // Return total costs before failures
  return floatTotalNotFailures;
}


//=============================================================
// calcFailures - returns failure costs for object
//=============================================================
function calcFailures()
{
  var floatFailures;

  // Calculations based on spreadsheet
  floatFailures = calcTotalNotFailures() / 100.0 * floatFailureRate;

  // Return floatOther cost
  return floatFailures;
}


//=============================================================
// grabInputs - saves input values as globals and cookies
//=============================================================
function grabInputs()
{
  // Copy all inputs to global variables
  floatObjectWeight    = Number(document.getElementById('object weight').value);
  floatPrintingTime    = Number(document.getElementById('printing time').value);
  floatElectricTariff  = Number(document.getElementById('electric tariff').value);
  floatPrinterPower    = Number(document.getElementById('printer power').value);
  floatFilamentCost    = Number(document.getElementById('filament cost').value);
  floatPrinterPurchase = Number(document.getElementById('printer purchase').value);
  floatPrinterLife     = Number(document.getElementById('printer life').value);
  floatPrinterUse      = Number(document.getElementById('printer use').value);
  floatRepairRate      = Number(document.getElementById('repair rate').value);
  floatOtherCosts      = Number(document.getElementById('other costs').value);
  floatFailureRate     = Number(document.getElementById('failure rate').value);
}


//=============================================================
// inputsValid - validate all inputs
//=============================================================
function inputsValid()
{
  var boolIsInvalid;

  // Check whether ALL inputs are valid numbers
  boolIsInvalid =
    isNaN(floatObjectWeight) ||
    isNaN(floatPrintingTime) ||
    isNaN(floatElectricTariff) ||
    isNaN(floatPrinterPower) ||
    isNaN(floatFilamentCost) ||
    isNaN(floatPrinterPurchase) ||
    isNaN(floatPrinterLife) ||
    isNaN(floatPrinterUse) ||
    isNaN(floatRepairRate) ||
    isNaN(floatOtherCosts) ||
    isNaN(floatFailureRate);

  // Return true only if all inputs are valid
  return !(boolIsInvalid);
}


//=============================================================
// calcTotal - returns total costs based on variables, not inputs
//=============================================================
function calcTotal()
{
  var floatTotal = 0.0;

  // If inputs are valid, calc total, else alert user  
  if (inputsValid())
  {
    floatTotal = calcTotalNotFailures() + calcFailures();
  }
  else
  {
    alert("Some input fields contain non-numeric values (ie, letters or symbols). Please correct them, then re-calculate!");
  }

  // Return the total
  return floatTotal;
}


//=============================================================
// displayTotal - displays total costs for object
//=============================================================
function displayTotal()
{
  var floatTotal;

  // Copy inputs to global variables
  grabInputs();

  // Save all inputs as cookies
  saveCookies()

  // Calculate total
  floatTotal = calcTotal();

  // Only display new total if inputs were valid
  if (inputsValid())
  {
    document.getElementById('total cost').value = floatTotal.toFixed(2);
  }
}


//=============================================================
// resetDefaults - reset all input values to defaults
//=============================================================
function resetDefaults()
{
  // Set all input variables to default values
  floatObjectWeight    = "100";
  floatPrintingTime    = "5";
  floatElectricTariff  = "0.0568";
  floatPrinterPower    = "50";
  floatFilamentCost    = "34.19";
  floatPrinterPurchase = "1576";
  floatPrinterLife     = "3";
  floatPrinterUse      = "2";
  floatRepairRate      = "10";
  floatOtherCosts      = "0.1";
  floatFailureRate     = "10";
}


//=============================================================
// displayValues - outputs all global values to the screen
//=============================================================
function displayValues()
{
  // Output all global values to the screen
  document.getElementById('object weight').value = floatObjectWeight;
  document.getElementById('printing time').value = floatPrintingTime;
  document.getElementById('electric tariff').value = floatElectricTariff;
  document.getElementById('printer power').value = floatPrinterPower;
  document.getElementById('filament cost').value = floatFilamentCost;
  document.getElementById('printer purchase').value = floatPrinterPurchase;
  document.getElementById('printer life').value = floatPrinterLife;
  document.getElementById('printer use').value = floatPrinterUse;
  document.getElementById('repair rate').value = floatRepairRate;
  document.getElementById('other costs').value = floatOtherCosts;
  document.getElementById('failure rate').value = floatFailureRate;
  displayTotal();
}


//=============================================================
// saveCookies - saves all input variables as cookies
//=============================================================
function saveCookies()
{
  setCookie("floatObjectWeight", floatObjectWeight, COOKIE_DAYS);
  setCookie("floatPrintingTime", floatPrintingTime, COOKIE_DAYS);
  setCookie("floatElectricTariff", floatElectricTariff, COOKIE_DAYS);
  setCookie("floatPrinterPower", floatPrinterPower, COOKIE_DAYS);
  setCookie("floatFilamentCost", floatFilamentCost, COOKIE_DAYS);
  setCookie("floatPrinterPurchase", floatPrinterPurchase, COOKIE_DAYS);
  setCookie("floatPrinterLife", floatPrinterLife, COOKIE_DAYS);
  setCookie("floatPrinterUse", floatPrinterUse, COOKIE_DAYS);
  setCookie("floatRepairRate", floatRepairRate, COOKIE_DAYS);
  setCookie("floatOtherCosts", floatOtherCosts, COOKIE_DAYS);
  setCookie("floatFailureRate", floatFailureRate, COOKIE_DAYS);
}


//=============================================================
// loadCookies - loads all input variables from cookies
//=============================================================
function loadCookies()
{
  floatObjectWeight = getCookie("floatObjectWeight");
  floatPrintingTime = getCookie("floatPrintingTime");
  floatElectricTariff = getCookie("floatElectricTariff");
  floatPrinterPower = getCookie("floatPrinterPower");
  floatFilamentCost = getCookie("floatFilamentCost");
  floatPrinterPurchase = getCookie("floatPrinterPurchase");
  floatPrinterLife = getCookie("floatPrinterLife");
  floatPrinterUse = getCookie("floatPrinterUse");
  floatRepairRate = getCookie("floatRepairRate");
  floatOtherCosts = getCookie("floatOtherCosts");
  floatFailureRate = getCookie("floatFailureRate");
}


//=============================================================
// deleteCookies - deletes all cookies for testing
//=============================================================
function deleteCookies()
{
  setCookie("floatObjectWeight", "");
  setCookie("floatPrintingTime", "");
  setCookie("floatElectricTariff", "");
  setCookie("floatPrinterPower", "");
  setCookie("floatFilamentCost", "");
  setCookie("floatPrinterPurchase", "");
  setCookie("floatPrinterLife", "");
  setCookie("floatPrinterUse", "");
  setCookie("floatRepairRate", "");
  setCookie("floatOtherCosts", "");
  setCookie("floatFailureRate", "");
}


//=============================================================
// afterPageLoad - called after the page loads
//=============================================================
function afterPageLoad()
{

  // If we have cookies saved then load them all
  if (getCookie("floatObjectWeight") != "")
  {
    loadCookies();
  }

  // Else if no cookies saves load default values
  else
  {
    resetDefaults();
  }

  // Display values to user
  displayValues();
}