如何制作Makerspace NFC组件管理系统
https://v.qq.com/x/page/b0864nyxjjq.html通过使用Particle Photon和终端数据库以及网页界面,并采用NFC贴纸对电子组件进行追踪。
此项目需要用到的工具材料:
硬件组件光子(Particle Photon)物联网开发板RC522 NFC标记阅读器OLED 2828 262K色 全彩显示模块Adafruit电容式触摸传感器 -MPR121NFC贴纸* 40
软件应用程序和在线服务Autodesk Fusion 360
粒子搭建Web IDEMySQL
NodeJS手动工具和制造设备3D打印机烙铁
故事:
目的 想象一下,作为创客空间的所有者,您可以自行组织和跟踪仓库内的设备。有时您的成员可能会借用这些组件但是并没有归还给您,或者他们将自己的工具材料带来后并将二者组装起来。这就是为什么我需要创建一个单独的库存管理系统,它使用NFC和仓储箱(bin)对具有物联网功能的组件进行组织和跟踪。
演示视频
https://v.qq.com/x/page/w08640xhlzk.html
总体布局 每个bin都会被分配一个名称、描述、一般类型,以及与其贴纸相对应的NFC UID。当零件进入bin时,每个零件都会有一个名称、描述、数量、类型,以及它所属bin的ID。所有这些数据都托管在MySQL数据库中。我使用NodeJS网络服务器创建了一个云API,然后可以对MySQL数据库执行某些操作,例如创建新组件或删除bin。在硬件方面,我使用带128x128 OLED屏幕和NFC读取器的Particle Photon,以及用于虚拟按钮的MPR121。
我还创建了一个网页,允许完全访问API,以便能够轻松、干净地更改几乎所有关于bin或组件的内容。
网络服务器我决定使用最适合我的用例的Express库,因为它允许创建简单的RESTful API,并且路径创建也非常简单。我开始使用npm安装express,以及cors和mysql。然后我用“require('包名package_name ')”将它们放置在顶部全局定义程序里面。我使用MySQL库的createPool函数连接到MySQL数据库,因为它能够轻松安全地创建和释放连接。每个API路径都有自己的功能,其中“app.post”用于POST请求,“app.get”用于GET请求。
字符串是发送数据的路径,例如“/parts/get_all_bins”。函数内容各不相同,但通常每个函数都建立与数据库的连接,解析请求数据,并执行某项查询。在数据库和设备之间添加缓冲区会创建一层安全控制区。
MySQL数据库 那么虽然目前存在一种访问和更改数据的方法,但是数据究竟存储在何处或如何存储?当我安装MySQL数据库时,我还安装了MySQL Workbench,它允许用户对其数据库进行管理。我创建了名为“components”的新模式,并创建了两个表:parts和bin。
每张表都需要不同的列,因为bin没有具体数量,而且组件不需要NFC UID。
我还创建了需要登录密码的新用户,以便与NodeJS服务器同时使用。如果有人获得对服务器代码的访问权限,那么执行此操作而不是使用root密码会大大提高安全性。
NFC RFID标签 当我第一次开始这个项目时,我只有几张NFC卡,所以我必须找到一种新的数据存储和扫描方法。然后我去了AliExpress寻找更好的媒介。我看到了NFC贴纸,它贴有一个非常小的天线和芯片,但是整个纸张非常薄而且很小。这样我们就可以将它们粘在bin上并轻松读取。
硬件 那么bin究竟以何种方式进行扫描,数量如何变化?对于这个问题,我使用RC522 RFID阅读器读取NFC标签。为了显示数据和指令,我使用了一个使用SSD1351控制器的128x128 OLED屏幕。由于此项目适用于创客空间,我希望避免使用物理按钮,因为它们可能会出现磨损。MPR121电容式触控板价格低廉并且具有I2C接口,最终被我选用。
它最多可以处理12个不同的频道。在我的设计方案中,我增加3个附有1/4英寸铜带的地方。这些铜片在触摸时可以充当按钮。
硬件代码 由于系统需要通过一系列繁琐的步骤进行创建,因此我开发了一个系统,该系统使用状态机对显示的页面进行控制。它按照以下顺序依次排列:搜索选项卡->选择bin ->显示bin ->显示组件->更改数量。为了解析来自Web服务器的响应,我使用了SparkJson库。在每个阶段,请求会自动生成并将其发送到Web服务器。
网页 这是整个项目中最难更正的部分。它包含三个组件:HTML、JavaScript和CSS。
由于我还是CSS新手,我使用的是W3 School的W3.CSS课程。为了确保界面的简洁,我制作了一个简单的按钮网格,每个按钮对应一个弹出的模态卡。每张模态卡右上角都有一个关闭按钮。列表箱和列表项等按钮显示一个在单击时更新的列表中。添加新项目和添加bin等按钮都包含在一个表单内。
JavaScript代码过于复杂,无法在本文中进行解释,但是它基本上包含在提交表单时调用的各种函数中。某些函数还会填充选择元素和表。
用法 如需使用该系统,用户将首先通过输入其名称和其他数据来填充他们所拥有的bin列表。然后按照类似的方式创建组件。如有需要,通过一个按钮即可批量创建组件,例如塞满各种电阻值的bin。一旦所有事情准备就绪,那么现在就可以使用photon对bin进行扫描了。
未来计划 在未来,我希望扩展系统,使其包括登录和所有权方面的内容。用户可以扫描他们的makerspace RFID卡,然后访问他们自己的个人bin。
原理图
代码 物理ReaderC/C++
// 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 rstD5
#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;
enum States {
SEARCH_FOR_CARD,
SELECT_BIN,
DISPLAY_BIN,
DISPLAY_PART,
CHANGE_QUANTITY
};
struct card_uid{
int size;
int id_digits;
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;
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"]["id"];
const char* name = root["rows"]["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"]["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 < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte, HEX);
current_card.id_string += mfrc522.uid.uidByte < 0x10 ? " 0" : " ";
current_card.id_string += String(mfrc522.uid.uidByte, HEX);
current_card.id_digits = mfrc522.uid.uidByte;
}
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);
response.send(result);
});
});
});
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);
response.send(result);
});
});
});
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网页 <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网页 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.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
原文地址:https://www.dfrobot.com/blog-1234.html
particle photon挺好用的 超级实惠的黑科技
页:
[1]