查看: 1801|回复: 2

[项目分享] 如何制作Makerspace NFC组件管理系统

[复制链接]

通过使用Particle Photon和终端数据库以及网页界面,并采用NFC贴纸对电子组件进行追踪。


此项目需要用到的工具材料:


硬件组件
RC522 NFC标记阅读器
Adafruit电容式触摸传感器 -  MPR121


软件应用程序和在线服务
Autodesk Fusion 360
粒子搭建Web IDE
MySQL
NodeJS
手动工具和制造设备


故事:

目的
想象一下,作为创客空间的所有者,您可以自行组织和跟踪仓库内的设备。有时您的成员可能会借用这些组件但是并没有归还给您,或者他们将自己的工具材料带来后并将二者组装起来。这就是为什么我需要创建一个单独的库存管理系统,它使用NFC和仓储箱(bin)对具有物联网功能的组件进行组织和跟踪。


1dsc_0154_iXILltXxyA.jpg
2dsc_0156_xpZuDjGf4v.jpg
3dsc_0157_oZ2uLW6mr6.jpg


演示视频



总体布局
每个bin都会被分配一个名称、描述、一般类型,以及与其贴纸相对应的NFC UID。当零件进入bin时,每个零件都会有一个名称、描述、数量、类型,以及它所属bin的ID。所有这些数据都托管在MySQL数据库中。我使用NodeJS网络服务器创建了一个云API,然后可以对MySQL数据库执行某些操作,例如创建新组件或删除bin。在硬件方面,我使用带128x128 OLED屏幕和NFC读取器的Particle Photon,以及用于虚拟按钮的MPR121。
4 fusion1_9demrZxeot.jpg

我还创建了一个网页,允许完全访问API,以便能够轻松、干净地更改几乎所有关于bin或组件的内容。


5 dsc_0160_Hrxq5bU5NH.jpg


网络服务器
我决定使用最适合我的用例的Express库,因为它允许创建简单的RESTful API,并且路径创建也非常简单。我开始使用npm安装express,以及cors和mysql。然后我用“require('包名package_name ')”将它们放置在顶部全局定义程序里面。我使用MySQL库的createPool函数连接到MySQL数据库,因为它能够轻松安全地创建和释放连接。每个API路径都有自己的功能,其中“app.post”用于POST请求,“app.get”用于GET请求。

字符串是发送数据的路径,例如“/parts/get_all_bins”。函数内容各不相同,但通常每个函数都建立与数据库的连接,解析请求数据,并执行某项查询。在数据库和设备之间添加缓冲区会创建一层安全控制区。

6 code4_y90CRcgLO1.jpg

MySQL数据库
那么虽然目前存在一种访问和更改数据的方法,但是数据究竟存储在何处或如何存储?当我安装MySQL数据库时,我还安装了MySQL Workbench,它允许用户对其数据库进行管理。我创建了名为“components”的新模式,并创建了两个表:parts和bin。
7 db1_rGUOg2JTXe.jpg

每张表都需要不同的列,因为bin没有具体数量,而且组件不需要NFC UID。
8 db2_TQVeFYBHWg.jpg 9 db3_azhHI4PyG5.jpg 10 db4_FoLjMwfkTa.jpg 11 db5_R5q94sKgQy.jpg

我还创建了需要登录密码的新用户,以便与NodeJS服务器同时使用。如果有人获得对服务器代码的访问权限,那么执行此操作而不是使用root密码会大大提高安全性。


NFC RFID标签
当我第一次开始这个项目时,我只有几张NFC卡,所以我必须找到一种新的数据存储和扫描方法。然后我去了AliExpress寻找更好的媒介。我看到了NFC贴纸,它贴有一个非常小的天线和芯片,但是整个纸张非常薄而且很小。这样我们就可以将它们粘在bin上并轻松读取。

12 dsc_0151_Txz2RtGVP5.jpg

13 dsc_0168_BSaKJNNcF2.jpg

硬件
那么bin究竟以何种方式进行扫描,数量如何变化?对于这个问题,我使用RC522 RFID阅读器读取NFC标签。为了显示数据和指令,我使用了一个使用SSD1351控制器的128x128 OLED屏幕。由于此项目适用于创客空间,我希望避免使用物理按钮,因为它们可能会出现磨损。MPR121电容式触控板价格低廉并且具有I2C接口,最终被我选用。

14 dsc_0161_dEkHDl1KZO.jpg


它最多可以处理12个不同的频道。在我的设计方案中,我增加3个附有1/4英寸铜带的地方。这些铜片在触摸时可以充当按钮。
15 fusion4_61FMTq7XKO.jpg
16 dsc_0213_zHRS0wjIkI.jpg


硬件代码
由于系统需要通过一系列繁琐的步骤进行创建,因此我开发了一个系统,该系统使用状态机对显示的页面进行控制。它按照以下顺序依次排列:搜索选项卡->选择bin ->显示bin ->显示组件->更改数量。为了解析来自Web服务器的响应,我使用了SparkJson库。在每个阶段,请求会自动生成并将其发送到Web服务器。


17 particle1_JcREyOr66D.jpg

网页
这是整个项目中最难更正的部分。它包含三个组件:HTML、JavaScript和CSS。

18 code1_tDsQJzwZLB.jpg
19 code2_rFPl0u4atS.jpg


由于我还是CSS新手,我使用的是W3 School的W3.CSS课程。为了确保界面的简洁,我制作了一个简单的按钮网格,每个按钮对应一个弹出的模态卡。每张模态卡右上角都有一个关闭按钮。列表箱和列表项等按钮显示一个在单击时更新的列表中。添加新项目和添加bin等按钮都包含在一个表单内。


20 web1_3geRGjGMja.jpg 21 web2_fY8w5qpG4A.jpg 22 web3_LDmCWHcMcM.jpg 23 web4_njsoAjmW1k.jpg 24 web5_XaEMpaH9mb.jpg 25 web6_aHcVxxykKE.jpg 26 web7_yZAIUQzmLe.jpg 27 web8_LOm7NMilga.jpg

JavaScript代码过于复杂,无法在本文中进行解释,但是它基本上包含在提交表单时调用的各种函数中。某些函数还会填充选择元素和表。


28 code3_VBn4rYzxkd.jpg


用法
如需使用该系统,用户将首先通过输入其名称和其他数据来填充他们所拥有的bin列表。然后按照类似的方式创建组件。如有需要,通过一个按钮即可批量创建组件,例如塞满各种电阻值的bin。一旦所有事情准备就绪,那么现在就可以使用photon对bin进行扫描了。


29 dsc_0215_3bTmjLqKCL.jpg


未来计划
在未来,我希望扩展系统,使其包括登录和所有权方面的内容。用户可以扫描他们的makerspace RFID卡,然后访问他们自己的个人bin。


原理图
30 schematic_QPkDgGvTGn.png

代码
物理ReaderC/C++

[AppleScript] 纯文本查看 复制代码
[/align]// This #include statement was automatically added by the Particle IDE.

#include <Adafruit_MPR121.h>

 

// This #include statement was automatically added by the Particle IDE.

#include <MFRC522.h>

 

// This #include statement was automatically added by the Particle IDE.

#include <SparkJson.h>

 

#include "application.h"

#include "HttpClient.h"

 

#include "Particle.h"

 

#define cs   D4

#define sclk A3

#define mosi A5

#define rst  D5

#define dc   D6

#define SS_PIN A2

#define RST_PIN D2

 

#define LEFT 0

#define CENTER 2

#define RIGHT 4

 

// Color definitions

#define        BLACK           0x0000

#define        BLUE            0x001F

#define        RED             0xF800

#define        GREEN           0x07E0

#define CYAN            0x07FF

#define MAGENTA         0xF81F

#define YELLOW          0xFFE0  

#define WHITE           0xFFFF

 

#include "Adafruit_mfGFX/Adafruit_mfGFX.h"

#include "Adafruit_SSD1351_Photon.h"

 

// Option 1: Hardware SPI - uses some analog pins, but much faster

Adafruit_SSD1351 tft = Adafruit_SSD1351(cs, dc, rst);

Adafruit_MPR121 cap = Adafruit_MPR121();

MFRC522 mfrc522(SS_PIN, RST_PIN);

 

 

HttpClient http;

http_header_t headers[] = {

    { "Content-Type", "application/json" },

    {"Accept", "*/*"},

    {NULL, NULL}

};

 

http_request_t request;

http_response_t response;

 

uint16_t lasttouched = 0;

uint16_t currtouched = 0;

 

char char_buf[500];

 

enum States {

    SEARCH_FOR_CARD,

    SELECT_BIN,

    DISPLAY_BIN,

    DISPLAY_PART,

    CHANGE_QUANTITY

};

 

struct card_uid{

    int size;

    int id_digits[7];

    String id_string;

} current_card;

 

int bin_id = 0, part_id = 0, part_qty = 0;;

 

States state = SEARCH_FOR_CARD;

 

void setup(void) {

  StaticJsonBuffer<400> jsonBuffer;

  Serial.begin(9600);

  Serial.print("hello!");

  tft.begin();

  reset_screen();

  mfrc522.setSPIConfig();

  mfrc522.PCD_Init();        // Init MFRC522 card

  cap.begin(0x5A);

  request.hostname = "IP address goes here";

  request.port = 3010;

}

 

void loop() {

  switch(state){

      case SEARCH_FOR_CARD:

        reset_screen();

        Serial.println("Scan a MIFARE Classic card.");

        tft.setTextSize(2);

        tft.println("Waiting for card to be scanned");

        current_card.id_string = "";

    wait_for_card();

    state = SELECT_BIN;

        break;

      case SELECT_BIN:

        select_bin();

        break;

      case DISPLAY_BIN:

        part_id = display_parts();

        //delay(1000);

        break;

      case DISPLAY_PART:

        display_part(part_id);

        //delay(1000);

        break;

      case CHANGE_QUANTITY:

        change_quantity(part_id);

        //delay(1000);

        break;

  }

}

 

void change_quantity(int item_id){

    request.path = "/parts/change_amount";

    reset_screen();

    int amount = 0, quantity = part_qty;

    String inc_dec = "";

    tft.setTextSize(1);

    tft.println("Change  |  New amount");

    tft.setCursor(0,120);

    tft.println("Increase|Set|Decrease");

    tft.setTextSize(3);

    while(1){

        delay(200);

        Particle.process();

        tft.fillRect(0,40,128,60,BLACK);

        tft.setCursor(20,45);

        tft.print(amount);

        tft.print(" | ");

        tft.print(quantity);

        while(1){

            currtouched = cap.touched();

            Particle.process();

            if((currtouched & _BV(LEFT))){

                amount++;

                quantity++;

                break;

            }

            else if((currtouched & _BV(CENTER))){

                if(amount >= 0){

                    inc_dec = "true";

                }

                else{

                    inc_dec = "false";

                }

                request.body = "{\"id\":"+String(item_id)+",\"inc_dec\":"+inc_dec+",\"amount\":"+String(abs(amount))+"}";

                http.post(request,response, headers);

                reset_screen();

                tft.setTextSize(2);

                tft.println("Success!");

                delay(2000);

                state = SEARCH_FOR_CARD;

                return;

            }

            else if((currtouched & _BV(RIGHT))){

                if(quantity>0){

                    amount--;

                    quantity--;

                    break;

                }

            }

        }

    }

}

 

void display_part(int item_id){

    reset_screen();

    StaticJsonBuffer<500> jsonBuffer;

    request.path = "/parts/get_part_info";

    request.body = "{\"id\":\""+String(item_id)+"\"}";

    http.post(request,response, headers);

    response.body.toCharArray(char_buf,500);

    JsonObject& root = jsonBuffer.parseObject(char_buf);

    int id = root["id"];

    const char* name = root["name"];

    int quantity = root["quantity"];

    const char* desc = root["description"];

    tft.print("Name: "); tft.println(name);tft.println();

    tft.print("Item id: "); tft.println(id);tft.println();

    tft.print("Quantity: "); tft.println(quantity);tft.println();

    tft.println("Description: ");tft.println(); tft.println(desc);tft.println();

    print_divider();

    tft.setCursor(0,120);

    tft.print("Back     Select");

    //delay(1000);

    while(1){

        currtouched = cap.touched();

        if((currtouched & _BV(LEFT))){

            state = DISPLAY_BIN;

            return;

        }

        else if((currtouched & _BV(CENTER))){

            state = CHANGE_QUANTITY;

            part_qty = quantity;

            return;

        }

        Particle.process();

    }

}

 

int display_parts(){

    int current_row = 0;

    static char new_char_buf[600];

    StaticJsonBuffer<1000> jsonBuffer;

    request.path = "/parts/get_parts_from_bin";

    request.body = "{\"bin_id\":\""+String(bin_id)+"\"}";

    http.post(request,response, headers);

    response.body.toCharArray(new_char_buf,600);

    Serial.println(new_char_buf);

    JsonObject& root = jsonBuffer.parseObject(const_cast<char*> (response.body.c_str()));

    reset_screen();

    if(!root.success()) Serial.println("couldnt parse");

    int entries = root["entries"];

    Serial.println(entries);

    while(1){

        reset_screen();

        Particle.process();

        //Serial.println(entry_num);

        int entry_num = entries;

        for(int row=0;row<entry_num;row++){

            int id = root["rows"][row]["id"];

            const char* name = root["rows"][row]["name"];

            Serial.println(name);

            if(current_row==row){

                tft.print("> ");

            }

            tft.println(name);

            //print_divider();

        }

        tft.setCursor(0,120);

        tft.print("Up    Select    Down");

        while(1){

            Particle.process();

            currtouched = cap.touched();

            if((currtouched & _BV(LEFT))){

                if(current_row>0){

                current_row--;

                break;

                }

            }

            else if((currtouched & _BV(RIGHT))){

                if(current_row<entry_num-1){

                current_row++;

                break;

                }

            }

            else if((currtouched & _BV(CENTER))){

                int id = root["rows"][current_row]["id"];

                state = DISPLAY_PART;

                return id;

            }

        }

    }

}

 

void select_bin(){

    StaticJsonBuffer<300> jsonBuffer;

    request.path = "/parts/get_bin_info";

    String rfid = current_card.id_string;

    request.body = "{\"rfid\":\""+rfid+"\"}";

    tft.println(request.body);

    http.post(request,response, headers);

    tft.println(response.body);

    response.body.toCharArray(char_buf,500);

    JsonObject& root = jsonBuffer.parseObject(char_buf);

    reset_screen();

    Serial.println(response.body);

    tft.print("Bin ID: ");

    int id = root["id"];

    bin_id = id;

    tft.println(id);

    tft.print("Bin RFID: ");

    tft.println(rfid);

    tft.println("Bin description: ");

    const char* desc = root["description"];

    tft.println(desc);

    print_divider();

    tft.setCursor(0,100);

    tft.println("Use this bin?");

    tft.println("Yes                No");

    int choice = 0;

    while(!choice){

        currtouched = cap.touched();

        Particle.process();

        if((currtouched & _BV(LEFT))){

            state = DISPLAY_BIN;

            return;

        }

        else if((currtouched & _BV(RIGHT))){

            state = SEARCH_FOR_CARD;

            return;

        }

        lasttouched = currtouched;

    }

}

 

void testdrawtext(char *text, uint16_t color) {

  tft.setCursor(0,0);

  tft.setTextColor(color);

  tft.print(text);

}

 

void print_divider(){

    tft.setTextSize(1);

    tft.println("----------");

}

 

void reset_screen(){

    tft.fillScreen(BLACK);

    tft.setCursor(0,0);

    tft.setTextColor(WHITE);

    tft.setTextSize(1);

}

 

void wait_for_card(){

    while(1){

        Particle.process();

        if (mfrc522.PICC_IsNewCardPresent()) {

            reset_screen();

            tft.setTextSize(2);

            tft.println("NFC tag found!");

            while(1){

                if (mfrc522.PICC_ReadCardSerial()) {

            Serial.print("Card UID:");

            current_card.size = mfrc522.uid.size;

            for (byte i = 0; i < mfrc522.uid.size; i++) {

            Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");

            Serial.print(mfrc522.uid.uidByte[i], HEX);

            current_card.id_string += mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ";

            current_card.id_string += String(mfrc522.uid.uidByte[i], HEX);

            current_card.id_digits[i] = mfrc522.uid.uidByte[i];

            }

            current_card.id_string.trim();

            Serial.println();

            delay(1000);

            return;

            }

            }

    }

    }

}

 

String get_bin_info(String rfid){

  request.path = "/parts/get_bin_info";

  request.body = "{\"rfid\":\""+rfid+"\"}";

  http.post(request,response, headers);

  //tft.print(response.body);

  //delay(2000);

  return String(response.body);

}

 

Node Js WebserverJavaScript

 

const mysql = require('mysql');

var express = require('express');

var parser = require('body-parser');

const cors = require('cors');

 

var app = express();

 

app.use(parser.json({extended: true}));

app.use(cors());

app.options('*',cors());

 

var con = mysql.createPool({

    host: "127.0.0.1",

    user: "username",

    password: "password",

    database: "components"

});

 

app.post("/parts/get_part_info", function(request, response){

    console.log(request.body);

    con.getConnection(function(err,connection){

        if(err) throw err;

        var query = `SELECT * FROM parts WHERE id = '${request.body.id}'`;

        connection.query(query,function(err, result){

            connection.release();

            if (err) throw err;

            console.log(result[0]);

            response.send(result[0]);

        });

    });

});

 

app.post("/parts/get_parts_from_bin", function(request, response){

    console.log(request.body);

    con.getConnection(function(err,connection){

        if(err) throw err;

        var query = `SELECT id, name FROM parts WHERE belongs_to = '${request.body.bin_id}'`;

        if(request.body.detailed !== undefined){

            query = `SELECT * FROM parts WHERE belongs_to = '${request.body.bin_id}'`;

        }

        connection.query(query,function(err, result){

            connection.release();

            if (err) throw err;

            res_json = {rows:result,entries:result.length};

            console.log(res_json);

            response.send(res_json);

        });

    });

});

 

app.post("/parts/get_bin_info", function(request, response){

    console.log(request.body);

    con.getConnection(function(err,connection){

        if(err) throw err;

        var query = `SELECT * FROM bins WHERE rfid = '${request.body.rfid}'`;

        console.log(query);

        connection.query(query,function(err, result){

            connection.release();

            if (err) throw err;

            console.log(result[0]);

            response.send(result[0]);

        });

    });

});

 

app.get("/parts/get_bins", function(request, response){

    con.getConnection(function(err,connection){

        if(err) throw err;

        var query = "SELECT * FROM bins";

        connection.query(query, function(err, result){

            connection.release();

            if(err) throw err;

            //var response_json = {entries_amount:result.length,rows:result}

            //console.log(result);

            response.send(result);

        });

        

    });

});

 

app.get("/parts/get_parts", function(request, response){

    con.getConnection(function(err,connection){

        if(err) throw err;

        var query = "SELECT * FROM parts";

        connection.query(query, function(err, result){

            connection.release();

            if(err) throw err;

            //var response_json = {entries_amount:result.length,rows:result}

            //console.log(result);

            response.send(result);

        });

        

    });

});

 

app.post("/parts/add_part", function(request, response){

    con.getConnection(function(err,connection){

        //console.log(request.body);

        if(err) throw err;

        var body = request.body;

        var query = `INSERT INTO parts (name, value, quantity, description, package, \

            belongs_to, is_SMD) VALUES ('${body.name}','${body.value}', \

            '${body.quantity}','${body.description}','${body.package}','${body.belongs}', \

            '${body.is_SMD}')`;

        connection.query(query, function(err, result){

            connection.release();

            if(err) throw err;

        });

        //response.send_header('Access-Control-Allow-Origin', '*')

        response.send("ok");

    });

});

 

app.post("/parts/add_bin", function(request, response){

    con.getConnection(function(err,connection){

        //console.log(request.body);

        if(err) throw err;

        var body = request.body;

        var query = `INSERT INTO bins (name, rfid, description, type, is_SMD, \

            is_mixed) VALUES ('${body.name}','${body.rfid}', \

            '${body.description}','${body.type}','${body.is_smd}','${body.is_mixed}')`;

        connection.query(query, function(err, result){

            connection.release();

            if(err) throw err;

        });

        //response.send_header('Access-Control-Allow-Origin', '*')

        response.send("ok");

    });

});

 

app.post("/parts/remove_bin", function(request, response){

    con.getConnection(function(err,connection){

        //console.log(request.body);

        if(err) throw err;

        var body = request.body;

        var query = `DELETE FROM bins WHERE (id = '${body.bin_id}')`;

        connection.query(query, function(err, result){

            //connection.release();

            if(err) throw err;

        });

        var query = `DELETE FROM parts WHERE (belongs_to = '${body.bin_id}')`;

        connection.query(query, function(err, result){

            connection.release();

            if(err) throw err;

        });

        //response.send_header('Access-Control-Allow-Origin', '*')

        response.send("ok");

    });

});

 

app.post("/parts/remove_item", function(request, response){

    con.getConnection(function(err,connection){

        if(err) throw err;

        var body = request.body;

        var query = `DELETE FROM parts WHERE (id = '${body.item_id}')`;

        connection.query(query, function(err,result){

            connection.release();

            if(err) throw err;

        });

        response.send("ok");

    });

});

 

app.post("/parts/change_amount", function(request,response){

    console.log(request.body);

    var amount = request.body.amount;

    var inc_dec = request.body.inc_dec;

    var item_id = request.body.id;

    if(inc_dec === true){

        var query = `UPDATE parts SET quantity = quantity + ${amount} WHERE id = ${item_id} and quantity >= 0`;

    }

     else if(inc_dec === false){

        var query = `UPDATE parts SET quantity = quantity - ${amount} WHERE id = ${item_id} and quantity >= 0+${amount}`;

    }

    console.log(query);

    con.getConnection(function(err,connection){

        if(err) throw err;

        connection.query(query,function(err, result){

            connection.release();

            if (err) throw err;

            console.log(`Successfully changed ${result.changedRows} entries`);

            response.send(`Successfully changed ${result.changedRows} entries`);

        });

    });

});

 

app.listen(3010);

 
HTML网页
[AppleScript] 纯文本查看 复制代码
<html>

<head>

    <title>Part Tracker</title>

    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

    <script type="text/javascript" src="https://cdn.jsdelivr.net/particle-api-js/5/particle.min.js"></script>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    <script src="part_tracker_script.js"></script>

    <link rel="stylesheet" href="part_tracker_styles.css">

</head>

<body class="w3-content" style="width: 100%">

    <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 50px; width: 100%;">

        <h1>Part Tracker Main Page</h1>

    </header>

    <div id="action_container" class="w3-display-container w3-white" style="height:100%;">

        <div id="actions" class="w3-display-top w3-center">

            <div class="w3-row-padding" style="margin-bottom: 50px;">

                <div class="w3-col s4 item" id="add_new_bulk_item">

                    <button class="modal_button w3-button w3-white w3-border w3-round"

                    onclick="document.getElementById('add_bulk_item').style.display='block';">

                        <p>Add new items in bulk</p>

                    </button>

                </div>

                <div class="w3-col s4 item" id="list_bins">

                    <button class="modal_button w3-button w3-white w3-border w3-round"

                    onclick="document.getElementById('list_all_bins').style.display='block';refresh_selects();">

                        <p>List bins</p>

                    </button>

                </div>

                <div class="w3-col s4 item" id="list_items">

                    <button class="modal_button w3-button w3-white w3-border w3-round"

                    onclick="document.getElementById('list_all_items').style.display='block';">

                        <p>List items</p>

                    </button>

                </div>

            </div>

            <div class="w3-row-padding" style="margin-bottom: 50px;">

                    <div class="w3-col s4 item" id="add_new_item">

                        <button class="modal_button w3-button w3-white w3-border w3-round"

                        onclick="document.getElementById('add_one_item').style.display='block';">

                            <p>Add a new item</p>

                        </button>

                    </div>

                    <div class="w3-col s4 item" id="remove_item_button">

                        <button class="modal_button w3-button w3-white w3-border w3-round"

                        onclick="document.getElementById('remove_item').style.display='block';">

                            <p>Remove item</p>

                        </button>

                    </div>

                    <div class="w3-col s4 item" id="list_items_btn">

                        <button class="modal_button w3-button w3-white w3-border w3-round"

                        onclick="document.getElementById('list_items_from_bin').style.display='block';">

                            <p>List items in a bin</p>

                        </button>

                    </div>

            </div>

            <div class="w3-row-padding" style="margin-bottom: 50px;">

                    <div class="w3-col s4 item" id="change_qty_btn">

                        <button class="modal_button w3-button w3-white w3-border w3-round"

                        onclick="document.getElementById('change_qty').style.display='block';">

                            <p>Change item quantity</p>

                        </button>

                    </div>

                    <div class="w3-col s4 item" id="add_bin_btn">

                        <button class="modal_button w3-button w3-white w3-border w3-round"

                        onclick="document.getElementById('add_bin').style.display='block';">

                            <p>Add bin</p>

                        </button>

                    </div>

                    <div class="w3-col s4 item" id="remove_bin_btn">

                        <button class="modal_button w3-button w3-white w3-border w3-round"

                        onclick="document.getElementById('remove_bin').style.display='block';">

                            <p>Remove bin</p>

                        </button>

                    </div>

            </div>

            <div class="w3-row-padding" style="margin-bottom: 25px;">

                <div class="w3-col s4 item w3-center" id="refresh_bins">

                    <button class="w3-button w3-white w3-border w3-round">

                        <p>Refresh bins</p>

                    </button>

                </div>

            </div>

        </div>

 

    </div>

 

<div id="list_all_items" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 25px;">

            <h2>View all parts</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 100%;">

            <span class="w3-button w3-display-topright">×</span>

            <table class="w3-table-all w3-hoverable" id="all_part_table">

                <tr class='w3-blue-gray'>

                    <th>Name</th>

                    <th>ID</th>

                    <th>Value</th>

                    <th>Quantity</th>

                    <th>Description</th>

                    <th>Package</th>

                    <th>Bin ID</th>

                    <th>Is SMD?</th>

                </tr>

            </table>

        </div>

    </div>

</div>

<div id="list_all_bins" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 25px;">

            <h2>View all bins</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 100%;">

            <span class="w3-button w3-display-topright">×</span>

            <table class="w3-table-all w3-hoverable" id="all_bin_table">

                <tr class='w3-blue-gray'>

                    <th>Name</th>

                    <th>ID</th>

                    <th>RFID UID</th>

                    <th>Type</th>

                    <th>Description</th>

                    <th>Is SMD?</th>

                    <th>Is mixed?</th>

                </tr>

            </table>

        </div>

    </div>

</div>

<div id="list_items_from_bin" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 25px;">

            <h2>View parts from bin</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 100%;">

            <span class="w3-button w3-display-topright">×</span>

            <select class="w3-select bin_select" name="bins" id="list_item_bin_select" style="margin-bottom: 25px;">

 

            </select>

            <table class="w3-table-all w3-hoverable" id="item_from_bin_table" style="display: none; width: 100%; margin-bottom:40px;">

            </table>

            <label style='display: none; margin-bottom: 28px; font-size: 40px;' class="w3-center" id="no_data_label">No data found!</label>

        </div>

    </div>

</div>

<div id="remove_item" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 25px;">

            <h2>Remove an item</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 100%;">

            <span class="w3-button w3-display-topright">×</span>

            <div class="w3-container" style="margin: auto; width: 100%;">

                <form id="remove_item_form" class="w3-container"

               >

                <label>Select a bin:</label>

                <select class="w3-select bin_select" name="bins" id="remove_item_select">

                </select>

                <label style="margin-top: 40px; display: none;" id="remove_item_item_label">Select an item to remove:</label>

                <select class="w3-select" name="items_sel" id="remove_item_item_select" style="display: none;">

                </select>

                <div class="w3-row-padding" style="margin-top: 30px;">

                    <div class="w3-center">

                        <input type="submit" value="Remove item"

                        class="w3-button w3-white w3-border">

                    </div>

                </div>

                </form>

            </div>

        </div>

    </div>

</div>

<div id="change_qty" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 25px;">

            <h2>Change the quantity of an item</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 100%;">

            <span class="w3-button w3-display-topright">×</span>

            <div class="w3-container" style="margin: auto; width: 100%;">

                <form id="change_item_form" class="w3-container"

               >

                <label>Select a bin:</label>

                <select class="w3-select bin_select" name="bins" id="change_qty_bin_select">

                </select>

                <label style="margin-top: 40px; display: none;" id="change_qty_label">Select an item to change:</label>

                <select class="w3-select" name="items_sel" id="change_qty_item_select" style="display: none;">

                </select>

                <div style="width: 25%;" class="w3-center">

                <label style="margin-top: 40px;">Change item quantity by </label>

                <input type="number" class="w3-input" name="num" value="0">

                </div>

                <div class="w3-row-padding" style="margin-top: 30px;">

                    <div class="w3-center">

                        <input type="submit" value="Change item"

                        class="w3-button w3-white w3-border">

                    </div>

                </div>

                </form>

            </div>

        </div>

    </div>

</div>

<div id="add_bin" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 25px;">

            <h2>Add a new bin</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 100%;">

            <span class="w3-button w3-display-topright">×</span>

            <div class="w3-container" style="margin: auto; width: 100%;">

                <form id="add_new_bin_form" class="w3-container"

               >

                    <label>New bin name</label>

                    <input type="text" class="w3-input" name="bin_name" style="margin-bottom: 20px;" required>

                    <label>RFID UID (Leave blank if none.)</label>

                    <input type="text" value="" class="w3-input" name="rfid" style="margin-bottom: 20px;">

                    <label>Description</label>

                    <input type="text" class="w3-input" name="desc" style="margin-bottom: 20px;" required>

                    <label>Bin type (RES, CAP, etc.)</label>

                    <input type="text" class="w3-input" name="type" style="margin-bottom: 20px;" required>

                    <label>Is SMD?</label>

                    <input type="radio" name="is_smd" class="w3-radio" value="1">

                    <label>Yes</label>

                    <input type="radio" name="is_smd" class="w3-radio" value="0" checked>

                    <label>No</label>

                    </br>

                    <label>Is it mixed? (SMD and non-SMD)</label>

                    <input type="radio" name="is_mixed" class="w3-radio" value="1">

                    <label>Yes</label>

                    <input type="radio" name="is_mixed" class="w3-radio" value="0" checked>

                    <label>No</label>

                    </br>

                    <div class="w3-row-padding w3-center" style="margin-top: 20px;">

                        <div class="w3-half">

                            <input type="submit" value="Create bin"

                            class="w3-button w3-white w3-border">

                        </div>

                        <div class="w3-half">

                            <input type="reset" value="Reset values" class="w3-button w3-white w3-border">

                        </div>

                    </div>

                </form>

            </div>

        </div>

    </div>

</div>

<div id="remove_bin" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 25px;">

            <h2>Remove a bin (Dangerous!)</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 100%;">

            <span class="w3-button w3-display-topright">×</span>

            <div id="remove_bin_container" class="w3-display-container w3-white">

                <form id="remove_bin_form" class="w3-container"

               >

                    <label>Bin:</label>

                    <select id="bin_remove_sel" name="bin_name" class="w3-select bin_select">

                    </select>

                    </br>

                    <div class="w3-panel w3-red w3-display-container">

                        <span

                        class="w3-button w3-large w3-display-topright">×</span>

                        <h3>Danger!</h3>

                        <p>Removing a bin also removes all associated parts!</p>

                    </div>

                    <div class="w3-row-padding" style="margin-top: 30px;">

                        <div class="w3-center">

                            <input type="submit" value="Remove bin"

                            class="w3-button w3-white w3-border">

                        </div>

                    </div>

                    

                </form>

            </div>

        </div>

    </div>

</div>

 

<div id="add_bulk_item" class="w3-modal w3-card-4" style="width:100%;">

    <div class="w3-modal-content w3-animate-top">

        <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 50px;">

            <h2>Add new items in bulk</h2>

        </header>

        <div class="w3-container" style="margin: auto; width: 400px;">

            <span class="w3-button w3-display-topright">×</span>

            <div id="add_new_set" class="w3-display-container w3-white">

                <form id="add_bulk_form" class="w3-container"

               >

                    <label>Bin:</label>

                    <select id="bin_select" name="bin_name" class="w3-select bin_select">

                    </select>

                    <label>Enter values separated by a comma:</label>

                    <textarea required id="values" name="value_str" rows="10",cols="40" value=""></textarea><br>

                    <label>Starting quantity of each part</label>

                    <input required type="number" class="w3-input" name="qty" value="0" min="0">

                    <label>Package (Leave blank if none.)</label>

                    <input type="text" name="pkg" class="w3-input"></br>

                    <label>Is this set of parts SMD?</label>

                    <input type="radio" name="is_smd" class="w3-radio" value="1">

                    <label>Yes</label>

                    <input type="radio" name="is_smd" class="w3-radio" value="0" checked>

                    <label>No</label>

                    </br>

                    <div class="w3-row-padding">

                        <div class="w3-half">

                            <input type="submit" value="Create parts"

                            class="w3-button w3-white w3-border">

                        </div>

                        <div class="w3-half">

                            <input type="reset" value="Reset values" class="w3-button w3-white w3-border">

                        </div>

                    </div>

                    

                </form>

            </div>

        </div>

    </div>

</div>

<div id="add_one_item" class="w3-modal w3-card-4" style="width:100%;">

        <div class="w3-modal-content w3-animate-top">

            <header class="w3-container w3-blue-gray w3-center" style="margin-bottom: 50px;">

                <h2>Add a new item</h2>

            </header>

            <div class="w3-container" style="margin: auto; width: 400px;">

                <span class="w3-button w3-display-topright">×</span>

                <div id="add_new_set" class="w3-display-container w3-white">

                    <form id="add_one_form" class="w3-container"

                    onsubmit="create_one_part('bin_add_one_select',this.item_name.value,this.qty.value,

                    this.is_smd.value,this.pkg.value,this.val.value,this.desc.value); return false">

                        <label>Bin:</label>

                        <select id="bin_add_one_select" name="bin_name" class="w3-select bin_select">

                        </select>

                        <label>Name of new item</label>

                        <input type="text" class="w3-input" name="item_name" required>

                        <label>Starting quantity of part</label>

                        <input type="number" class="w3-input" name="qty" value="0" min="0" required>

                        <label>Package (Leave blank if none.)</label>

                        <input type="text" name="pkg" class="w3-input"></br>

                        <label>Value (Leave blank if none.)</label>

                        <input type="text" name="val" class="w3-input"></br>

                        <label>Item Description</label>

                        <input type="text" name="desc" class="w3-input" required></br>

                        <label>Is this part SMD?</label>

                        <input type="radio" name="is_smd" class="w3-radio" value="1">

                        <label>Yes</label>

                        <input type="radio" name="is_smd" class="w3-radio" value="0" checked>

                        <label>No</label>

                        </br>

                        <div class="w3-row-padding">

                            <div class="w3-half">

                                <input type="submit" value="Create part"

                                class="w3-button w3-white w3-border">

                            </div>

                            <div class="w3-half">

                                <input type="reset" value="Reset values" class="w3-button w3-white w3-border">

                            </div>

                        </div>

                        

                    </form>

                </div>

            </div>

        </div>

</div>

</body>

</html>

 
Javascript网页
[AppleScript] 纯文本查看 复制代码
const ip = "ip address here"; //Make sure to change this

 

function create_parts(bin_sel, value_str, pkg,is_smd,qty){

    console.log(bin_sel);

    var sel_elem = document.getElementById(bin_sel);

    var bin_str = sel_elem.options[sel_elem.selectedIndex].value;

    var bin_parsed = JSON.parse(bin_str);

    var id = bin_parsed.id;

    var type = bin_parsed.type;

    var val_array = value_str.split(",");

    console.log(val_array);

    val_array.forEach(element => {

        console.log(element);

        var smd_modify = "";

        if(is_smd==="1"){

            smd_modify = "SMD"

        }

        var modifier = `${pkg} ${smd_modify}`;

        var dataString = {

            name: `${modifier} ${element} ${type}`,

            value: `${ele


 




gada888  版主

发表于 2019-4-27 13:24:40

particle photon挺好用的
回复 支持 反对

使用道具 举报

gray6666  高级技匠

发表于 2019-4-28 14:15:08

超级实惠的黑科技
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
wifi气象站

硬件清单

btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2019 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail