diff --git a/config.js b/config.js
new file mode 100644
index 0000000..b068a61
--- /dev/null
+++ b/config.js
@@ -0,0 +1,17 @@
+// https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjYWtlVmVuZGluZyIsIm5hbWUiOiJKYXNoIEhzdSJ9.DSYy7W5a6iLSre1cmRaWBEdxYGu81jzdwdWnbnqRr4c
+
+module.exports = {
+ fbMesChatBotToken:
+ "EAAHGWe0Bo1IBABMq7O3G0ZCpZCwjCyzFpVXRNShYUqeDjJzrrkRWSCgcKvEehoYYizuBbaZCmx0bndc3YGVbHq0tvrmewq81qRkS5YFf5kbBc16jtawQTsUj9a5jazDAF35fLoGy1jBTnyxgMsACP7e0hLlZC75rZBWxGORqb98ozy9cq6UynV6px2YOX088ZD",
+ token:
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjYWtlVmVuZGluZyIsIm5hbWUiOiJKYXNoIEhzdSJ9.DSYy7W5a6iLSre1cmRaWBEdxYGu81jzdwdWnbnqRr4c",
+ subject: "cakeVending",
+ name: "Jash Hsu",
+ secret: "0919304983",
+ backendVersion: "cakeVendingBackend v1.0",
+ backendPort: 8081,
+ mqttBrokerPort: 1883,
+ mqttBrokerWSPort: 8000, //websockets
+ serverPort: 10010,
+ serverVersion: "cakeVendingServer v1.0",
+};
diff --git a/fbbot/.env.example b/fbbot/.env.example
new file mode 100644
index 0000000..a149b91
--- /dev/null
+++ b/fbbot/.env.example
@@ -0,0 +1,19 @@
+MESSENGER_PAGE_ID=
+MESSENGER_ACCESS_TOKEN=
+MESSENGER_APP_ID=
+MESSENGER_APP_SECRET=
+MESSENGER_VERIFY_TOKEN=
+
+WHATSAPP_ACCOUNT_SID=
+WHATSAPP_AUTH_TOKEN=
+WHATSAPP_PHONE_NUMBER=
+
+LINE_ACCESS_TOKEN=
+LINE_CHANNEL_SECRET=
+
+TELEGRAM_ACCESS_TOKEN=
+
+SLACK_ACCESS_TOKEN=
+SLACK_SIGNING_SECRET=
+
+VIBER_ACCESS_TOKEN=
diff --git a/fbbot/.eslintignore b/fbbot/.eslintignore
new file mode 100644
index 0000000..f06235c
--- /dev/null
+++ b/fbbot/.eslintignore
@@ -0,0 +1,2 @@
+node_modules
+dist
diff --git a/fbbot/.eslintrc.js b/fbbot/.eslintrc.js
new file mode 100644
index 0000000..40608a6
--- /dev/null
+++ b/fbbot/.eslintrc.js
@@ -0,0 +1,27 @@
+module.exports = {
+ parserOptions: {
+ ecmaVersion: 2018,
+ },
+ extends: ['eslint:recommended', 'prettier'],
+ env: {
+ node: true,
+ },
+ rules: {
+ 'prettier/prettier': [
+ 'error',
+ {
+ trailingComma: 'es5',
+ singleQuote: true,
+ },
+ ],
+ },
+ plugins: ['prettier'],
+ overrides: [
+ {
+ files: ['**/*.test.js'],
+ env: {
+ jest: true,
+ },
+ },
+ ],
+};
diff --git a/fbbot/.gitignore b/fbbot/.gitignore
new file mode 100644
index 0000000..3b088af
--- /dev/null
+++ b/fbbot/.gitignore
@@ -0,0 +1,63 @@
+# Taken from https://github.com/github/gitignore/blob/master/Node.gitignore
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# jest-junit
+junit.xml
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
diff --git a/fbbot/README.md b/fbbot/README.md
new file mode 100644
index 0000000..e7bdfd7
--- /dev/null
+++ b/fbbot/README.md
@@ -0,0 +1,62 @@
+This project was bootstrapped with
+[Bottender](https://github.com/Yoctol/bottender) init script.
+
+## Sending Feedback
+
+Always feel free to open an issue to
+[Bottender](https://github.com/Yoctol/bottender/issues) repository.
+
+## Configuration
+
+### The `bottender.config.js` File
+
+Bottender configuration file. You can use this file to provide settings for the session store and channels.
+
+### The `.env` File
+
+Bottender utilizes the [dotenv](https://www.npmjs.com/package/dotenv) package to load your environment variables when developing your app.
+
+To make the bot work, you must put required environment variables into your `.env` file.
+
+## Available Scripts
+
+In the project directory, you can run:
+
+### `npm run dev`
+
+Runs the app in development mode.
+The bot will automatically reload if you make changes to the code.
+By default, server runs on [http://localhost:5000](http://localhost:5000) and ngrok runs on [http://localhost:4040](http://localhost:4040).
+
+To run in [Console Mode](https://bottender.js.org/docs/en/the-basics-console-mode), provide the `--console` option:
+
+```sh
+npm run dev -- --console
+yarn dev --console
+```
+
+### `npm start`
+
+Runs the app in production mode.
+By default, server runs on [http://localhost:5000](http://localhost:5000).
+
+To run in [Console Mode](https://bottender.js.org/docs/en/the-basics-console-mode), provide the `--console` option:
+
+```sh
+npm start -- --console
+yarn start --console
+```
+
+### `npm run lint`
+
+Runs the linter rules using [Eslint](https://eslint.org/).
+
+### `npm test`
+
+Runs the test cases using [Jest](https://jestjs.io/).
+
+## Learn More
+
+To learn Bottender, check out the [Bottender documentation](https://bottender.js.org/docs/en/getting-started).
+
+For more examples, see [Bottender examples](https://github.com/Yoctol/bottender/tree/master/examples).
diff --git a/fbbot/bottender.config.js b/fbbot/bottender.config.js
new file mode 100644
index 0000000..59168c2
--- /dev/null
+++ b/fbbot/bottender.config.js
@@ -0,0 +1,67 @@
+module.exports = {
+ session: {
+ driver: "memory",
+ stores: {
+ memory: {
+ maxSize: 500,
+ },
+ file: {
+ dirname: ".sessions",
+ },
+ redis: {
+ port: 6379,
+ host: "127.0.0.1",
+ password: "auth",
+ db: 0,
+ },
+ mongo: {
+ url: "mongodb://localhost:27017",
+ collectionName: "sessions",
+ },
+ },
+ },
+ initialState: {},
+ channels: {
+ messenger: {
+ enabled: true,
+ path: "/webhooks/messenger",
+ pageId: process.env.MESSENGER_PAGE_ID,
+ accessToken: process.env.MESSENGER_ACCESS_TOKEN,
+ appId: process.env.MESSENGER_APP_ID,
+ appSecret: process.env.MESSENGER_APP_SECRET,
+ verifyToken: process.env.MESSENGER_VERIFY_TOKEN,
+ },
+ whatsapp: {
+ enabled: false,
+ path: "/webhooks/whatsapp",
+ accountSid: process.env.WHATSAPP_ACCOUNT_SID,
+ authToken: process.env.WHATSAPP_AUTH_TOKEN,
+ phoneNumber: process.env.WHATSAPP_PHONE_NUMBER,
+ },
+ line: {
+ enabled: false,
+ path: "/webhooks/line",
+ accessToken: process.env.LINE_ACCESS_TOKEN,
+ channelSecret: process.env.LINE_CHANNEL_SECRET,
+ },
+ telegram: {
+ enabled: false,
+ path: "/webhooks/telegram",
+ accessToken: process.env.TELEGRAM_ACCESS_TOKEN,
+ },
+ slack: {
+ enabled: false,
+ path: "/webhooks/slack",
+ accessToken: process.env.SLACK_ACCESS_TOKEN,
+ signingSecret: process.env.SLACK_SIGNING_SECRET,
+ },
+ viber: {
+ enabled: false,
+ path: "/webhooks/viber",
+ accessToken: process.env.VIBER_ACCESS_TOKEN,
+ sender: {
+ name: "xxxx",
+ },
+ },
+ },
+};
diff --git a/fbbot/index.js b/fbbot/index.js
new file mode 100644
index 0000000..3fc7798
--- /dev/null
+++ b/fbbot/index.js
@@ -0,0 +1 @@
+module.exports = require('./src');
diff --git a/fbbot/jest.config.js b/fbbot/jest.config.js
new file mode 100644
index 0000000..c36b12a
--- /dev/null
+++ b/fbbot/jest.config.js
@@ -0,0 +1,9 @@
+module.exports = {
+ testEnvironment: 'node',
+ moduleFileExtensions: ['js'],
+ transformIgnorePatterns: ['/node_modules/'],
+ testMatch: [
+ '/**/__tests__/**/*.js',
+ '/**/*.{spec,test}.js',
+ ],
+};
diff --git a/fbbot/package.json b/fbbot/package.json
new file mode 100644
index 0000000..94abb88
--- /dev/null
+++ b/fbbot/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "fbbot",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "bottender dev",
+ "lint": "eslint . ",
+ "start": "bottender start",
+ "test": "jest"
+ },
+ "dependencies": {
+ "bottender": "1.4.1",
+ "eslint": "6.8.0",
+ "eslint-config-prettier": "6.11.0",
+ "eslint-plugin-prettier": "3.1.3",
+ "jest": "25.4.0",
+ "prettier": "2.0.5",
+ "axios": "^0.19.2",
+ "body-parser": "^1.19.0",
+ "cors": "^2.8.5",
+ "express": "^4.17.1",
+ "morgan": "^1.9.1"
+ }
+}
diff --git a/fbbot/src/index.js b/fbbot/src/index.js
new file mode 100644
index 0000000..5bc389b
--- /dev/null
+++ b/fbbot/src/index.js
@@ -0,0 +1,40 @@
+const express = require("express");
+const app = express();
+const http = require("http");
+const https = require("https");
+const fs = require("fs");
+const bodyParser = require("body-parser");
+const cors = require("cors");
+const morgan = require("morgan");
+const axios = require("axios");
+const config = require("../../config");
+
+app.use(cors());
+app.use(bodyParser.urlencoded({ extended: false }));
+app.use(bodyParser.text());
+app.use(morgan("dev"));
+
+app.get("/version", (req, res) => {
+ res.send(config.serverVersion);
+});
+
+let lastText = "initial";
+
+app.post("/module/offline", (req, res) => {
+ lastText = req.body;
+ res.sendStatus(200);
+});
+
+http.createServer(app).listen(config.serverPort, () => {
+ console.log("cake vending server listening on port " + config.serverPort);
+});
+
+module.exports = async function App(context) {
+ if (context.event.isText) {
+ if (context.event.text === "show offline") {
+ await context.sendText(lastText);
+ } else {
+ await context.sendText("welcome to cake vending fb bot");
+ }
+ }
+};
diff --git a/fbbot/src/index.test.js b/fbbot/src/index.test.js
new file mode 100644
index 0000000..5f1ef63
--- /dev/null
+++ b/fbbot/src/index.test.js
@@ -0,0 +1,7 @@
+const App = require('.');
+
+describe('index.js', () => {
+ it('should be defined', () => {
+ expect(App).toBeDefined();
+ });
+});
diff --git a/linebot/.env.example b/linebot/.env.example
new file mode 100644
index 0000000..a149b91
--- /dev/null
+++ b/linebot/.env.example
@@ -0,0 +1,19 @@
+MESSENGER_PAGE_ID=
+MESSENGER_ACCESS_TOKEN=
+MESSENGER_APP_ID=
+MESSENGER_APP_SECRET=
+MESSENGER_VERIFY_TOKEN=
+
+WHATSAPP_ACCOUNT_SID=
+WHATSAPP_AUTH_TOKEN=
+WHATSAPP_PHONE_NUMBER=
+
+LINE_ACCESS_TOKEN=
+LINE_CHANNEL_SECRET=
+
+TELEGRAM_ACCESS_TOKEN=
+
+SLACK_ACCESS_TOKEN=
+SLACK_SIGNING_SECRET=
+
+VIBER_ACCESS_TOKEN=
diff --git a/linebot/.eslintignore b/linebot/.eslintignore
new file mode 100644
index 0000000..f06235c
--- /dev/null
+++ b/linebot/.eslintignore
@@ -0,0 +1,2 @@
+node_modules
+dist
diff --git a/linebot/.eslintrc.js b/linebot/.eslintrc.js
new file mode 100644
index 0000000..40608a6
--- /dev/null
+++ b/linebot/.eslintrc.js
@@ -0,0 +1,27 @@
+module.exports = {
+ parserOptions: {
+ ecmaVersion: 2018,
+ },
+ extends: ['eslint:recommended', 'prettier'],
+ env: {
+ node: true,
+ },
+ rules: {
+ 'prettier/prettier': [
+ 'error',
+ {
+ trailingComma: 'es5',
+ singleQuote: true,
+ },
+ ],
+ },
+ plugins: ['prettier'],
+ overrides: [
+ {
+ files: ['**/*.test.js'],
+ env: {
+ jest: true,
+ },
+ },
+ ],
+};
diff --git a/linebot/.gitignore b/linebot/.gitignore
new file mode 100644
index 0000000..3b088af
--- /dev/null
+++ b/linebot/.gitignore
@@ -0,0 +1,63 @@
+# Taken from https://github.com/github/gitignore/blob/master/Node.gitignore
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# jest-junit
+junit.xml
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
diff --git a/linebot/README.md b/linebot/README.md
new file mode 100644
index 0000000..e7bdfd7
--- /dev/null
+++ b/linebot/README.md
@@ -0,0 +1,62 @@
+This project was bootstrapped with
+[Bottender](https://github.com/Yoctol/bottender) init script.
+
+## Sending Feedback
+
+Always feel free to open an issue to
+[Bottender](https://github.com/Yoctol/bottender/issues) repository.
+
+## Configuration
+
+### The `bottender.config.js` File
+
+Bottender configuration file. You can use this file to provide settings for the session store and channels.
+
+### The `.env` File
+
+Bottender utilizes the [dotenv](https://www.npmjs.com/package/dotenv) package to load your environment variables when developing your app.
+
+To make the bot work, you must put required environment variables into your `.env` file.
+
+## Available Scripts
+
+In the project directory, you can run:
+
+### `npm run dev`
+
+Runs the app in development mode.
+The bot will automatically reload if you make changes to the code.
+By default, server runs on [http://localhost:5000](http://localhost:5000) and ngrok runs on [http://localhost:4040](http://localhost:4040).
+
+To run in [Console Mode](https://bottender.js.org/docs/en/the-basics-console-mode), provide the `--console` option:
+
+```sh
+npm run dev -- --console
+yarn dev --console
+```
+
+### `npm start`
+
+Runs the app in production mode.
+By default, server runs on [http://localhost:5000](http://localhost:5000).
+
+To run in [Console Mode](https://bottender.js.org/docs/en/the-basics-console-mode), provide the `--console` option:
+
+```sh
+npm start -- --console
+yarn start --console
+```
+
+### `npm run lint`
+
+Runs the linter rules using [Eslint](https://eslint.org/).
+
+### `npm test`
+
+Runs the test cases using [Jest](https://jestjs.io/).
+
+## Learn More
+
+To learn Bottender, check out the [Bottender documentation](https://bottender.js.org/docs/en/getting-started).
+
+For more examples, see [Bottender examples](https://github.com/Yoctol/bottender/tree/master/examples).
diff --git a/linebot/bottender.config.js b/linebot/bottender.config.js
new file mode 100644
index 0000000..1332ba1
--- /dev/null
+++ b/linebot/bottender.config.js
@@ -0,0 +1,67 @@
+module.exports = {
+ session: {
+ driver: "memory",
+ stores: {
+ memory: {
+ maxSize: 500,
+ },
+ file: {
+ dirname: ".sessions",
+ },
+ redis: {
+ port: 6379,
+ host: "127.0.0.1",
+ password: "auth",
+ db: 0,
+ },
+ mongo: {
+ url: "mongodb://localhost:27017",
+ collectionName: "sessions",
+ },
+ },
+ },
+ initialState: {},
+ channels: {
+ messenger: {
+ enabled: false,
+ path: "/webhooks/messenger",
+ pageId: process.env.MESSENGER_PAGE_ID,
+ accessToken: process.env.MESSENGER_ACCESS_TOKEN,
+ appId: process.env.MESSENGER_APP_ID,
+ appSecret: process.env.MESSENGER_APP_SECRET,
+ verifyToken: process.env.MESSENGER_VERIFY_TOKEN,
+ },
+ whatsapp: {
+ enabled: false,
+ path: "/webhooks/whatsapp",
+ accountSid: process.env.WHATSAPP_ACCOUNT_SID,
+ authToken: process.env.WHATSAPP_AUTH_TOKEN,
+ phoneNumber: process.env.WHATSAPP_PHONE_NUMBER,
+ },
+ line: {
+ enabled: true,
+ path: "/webhooks/line",
+ accessToken: process.env.LINE_ACCESS_TOKEN,
+ channelSecret: process.env.LINE_CHANNEL_SECRET,
+ },
+ telegram: {
+ enabled: false,
+ path: "/webhooks/telegram",
+ accessToken: process.env.TELEGRAM_ACCESS_TOKEN,
+ },
+ slack: {
+ enabled: false,
+ path: "/webhooks/slack",
+ accessToken: process.env.SLACK_ACCESS_TOKEN,
+ signingSecret: process.env.SLACK_SIGNING_SECRET,
+ },
+ viber: {
+ enabled: false,
+ path: "/webhooks/viber",
+ accessToken: process.env.VIBER_ACCESS_TOKEN,
+ sender: {
+ name: "xxxx",
+ },
+ },
+ },
+};
diff --git a/linebot/index.js b/linebot/index.js
new file mode 100644
index 0000000..3fc7798
--- /dev/null
+++ b/linebot/index.js
@@ -0,0 +1 @@
+module.exports = require('./src');
diff --git a/linebot/jest.config.js b/linebot/jest.config.js
new file mode 100644
index 0000000..c36b12a
--- /dev/null
+++ b/linebot/jest.config.js
@@ -0,0 +1,9 @@
+module.exports = {
+ testEnvironment: 'node',
+ moduleFileExtensions: ['js'],
+ transformIgnorePatterns: ['/node_modules/'],
+ testMatch: [
+ '/**/__tests__/**/*.js',
+ '/**/*.{spec,test}.js',
+ ],
+};
diff --git a/linebot/package.json b/linebot/package.json
new file mode 100644
index 0000000..05761f8
--- /dev/null
+++ b/linebot/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "linebot",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "PORT=5001 bottender dev",
+ "lint": "eslint . ",
+ "start": "bottender start",
+ "test": "jest"
+ },
+ "dependencies": {
+ "bottender": "1.4.1",
+ "eslint": "6.8.0",
+ "eslint-config-prettier": "6.11.0",
+ "eslint-plugin-prettier": "3.1.3",
+ "jest": "25.4.0",
+ "prettier": "2.0.5",
+ "axios": "^0.19.2",
+ "body-parser": "^1.19.0",
+ "cors": "^2.8.5",
+ "express": "^4.17.1",
+ "morgan": "^1.9.1"
+ }
+}
diff --git a/linebot/src/index.js b/linebot/src/index.js
new file mode 100644
index 0000000..975d0ab
--- /dev/null
+++ b/linebot/src/index.js
@@ -0,0 +1,40 @@
+const express = require("express");
+const app = express();
+const http = require("http");
+const https = require("https");
+const fs = require("fs");
+const bodyParser = require("body-parser");
+const cors = require("cors");
+const morgan = require("morgan");
+const axios = require("axios");
+const config = require("../../config");
+
+app.use(cors());
+app.use(bodyParser.urlencoded({ extended: false }));
+app.use(bodyParser.text());
+app.use(morgan("dev"));
+
+app.get("/version", (req, res) => {
+ res.send(config.serverVersion);
+});
+
+let lastText = "initial";
+
+app.post("/module/offline", (req, res) => {
+ lastText = req.body;
+ res.sendStatus(200);
+});
+
+http.createServer(app).listen(config.serverPort, () => {
+ console.log("cake vending server listening on port " + config.serverPort);
+});
+
+module.exports = async function App(context) {
+ if (context.event.isText) {
+ if (context.event.text === "show offline") {
+ await context.sendText(lastText);
+ } else {
+ await context.sendText("welcome to cake vending line bot");
+ }
+ }
+};
diff --git a/linebot/src/index.test.js b/linebot/src/index.test.js
new file mode 100644
index 0000000..5f1ef63
--- /dev/null
+++ b/linebot/src/index.test.js
@@ -0,0 +1,7 @@
+const App = require('.');
+
+describe('index.js', () => {
+ it('should be defined', () => {
+ expect(App).toBeDefined();
+ });
+});
diff --git a/mechanic/8mm Acme Nut Block.SLDPRT b/mechanic/8mm Acme Nut Block.SLDPRT
deleted file mode 100644
index 67f570b..0000000
Binary files a/mechanic/8mm Acme Nut Block.SLDPRT and /dev/null differ
diff --git a/mechanic/8mm leadscrew 520mm.SLDPRT b/mechanic/8mm leadscrew 520mm.SLDPRT
deleted file mode 100644
index 86eb2ed..0000000
Binary files a/mechanic/8mm leadscrew 520mm.SLDPRT and /dev/null differ
diff --git a/mechanic/8mm leadscrew 540mm.SLDPRT b/mechanic/8mm leadscrew 540mm.SLDPRT
deleted file mode 100644
index a0b2494..0000000
Binary files a/mechanic/8mm leadscrew 540mm.SLDPRT and /dev/null differ
diff --git a/mechanic/Actuator End Mount 2.SLDPRT b/mechanic/Actuator End Mount 2.SLDPRT
deleted file mode 100644
index a928b21..0000000
Binary files a/mechanic/Actuator End Mount 2.SLDPRT and /dev/null differ
diff --git a/mechanic/Aluminum Spacer 3mm.SLDPRT b/mechanic/Aluminum Spacer 3mm.SLDPRT
deleted file mode 100644
index 5f23314..0000000
Binary files a/mechanic/Aluminum Spacer 3mm.SLDPRT and /dev/null differ
diff --git a/mechanic/Aluminum Spacer 40mm.SLDPRT b/mechanic/Aluminum Spacer 40mm.SLDPRT
deleted file mode 100644
index 0dc16db..0000000
Binary files a/mechanic/Aluminum Spacer 40mm.SLDPRT and /dev/null differ
diff --git a/mechanic/Aluminum Spacer 6mm.SLDPRT b/mechanic/Aluminum Spacer 6mm.SLDPRT
deleted file mode 100644
index 4a0bee9..0000000
Binary files a/mechanic/Aluminum Spacer 6mm.SLDPRT and /dev/null differ
diff --git a/mechanic/Aluminum Spacer 9mm.SLDPRT b/mechanic/Aluminum Spacer 9mm.SLDPRT
deleted file mode 100644
index e1af95d..0000000
Binary files a/mechanic/Aluminum Spacer 9mm.SLDPRT and /dev/null differ
diff --git a/mechanic/Assembly Arduino Mega RAMPS 1.4.SLDASM b/mechanic/Assembly Arduino Mega RAMPS 1.4.SLDASM
deleted file mode 100644
index 44bbc8b..0000000
Binary files a/mechanic/Assembly Arduino Mega RAMPS 1.4.SLDASM and /dev/null differ
diff --git a/mechanic/Ball Bearing 5 x 16 x 5.SLDPRT b/mechanic/Ball Bearing 5 x 16 x 5.SLDPRT
deleted file mode 100644
index 7e74be5..0000000
Binary files a/mechanic/Ball Bearing 5 x 16 x 5.SLDPRT and /dev/null differ
diff --git a/mechanic/Ball Bearing 8 x 16 x 5.SLDPRT b/mechanic/Ball Bearing 8 x 16 x 5.SLDPRT
deleted file mode 100644
index 4c73477..0000000
Binary files a/mechanic/Ball Bearing 8 x 16 x 5.SLDPRT and /dev/null differ
diff --git a/mechanic/Button Head Socket Cap Screw M3.SLDPRT b/mechanic/Button Head Socket Cap Screw M3.SLDPRT
deleted file mode 100644
index 2f3dd30..0000000
Binary files a/mechanic/Button Head Socket Cap Screw M3.SLDPRT and /dev/null differ
diff --git a/mechanic/Center Cutout 1.SLDBLK b/mechanic/Center Cutout 1.SLDBLK
deleted file mode 100644
index 5223255..0000000
Binary files a/mechanic/Center Cutout 1.SLDBLK and /dev/null differ
diff --git a/mechanic/Center Cutout 2.SLDBLK b/mechanic/Center Cutout 2.SLDBLK
deleted file mode 100644
index 6dff103..0000000
Binary files a/mechanic/Center Cutout 2.SLDBLK and /dev/null differ
diff --git a/mechanic/Double Tee Nut.SLDPRT b/mechanic/Double Tee Nut.SLDPRT
deleted file mode 100644
index 7c66fb3..0000000
Binary files a/mechanic/Double Tee Nut.SLDPRT and /dev/null differ
diff --git a/mechanic/Flexible Coupling 5mm x 8mm.SLDPRT b/mechanic/Flexible Coupling 5mm x 8mm.SLDPRT
deleted file mode 100644
index b39462f..0000000
Binary files a/mechanic/Flexible Coupling 5mm x 8mm.SLDPRT and /dev/null differ
diff --git a/mechanic/GT2 Timing Pulley 30 Tooth.SLDPRT b/mechanic/GT2 Timing Pulley 30 Tooth.SLDPRT
deleted file mode 100644
index c7208e7..0000000
Binary files a/mechanic/GT2 Timing Pulley 30 Tooth.SLDPRT and /dev/null differ
diff --git a/mechanic/HEATSINK FOR A4988.SLDPRT b/mechanic/HEATSINK FOR A4988.SLDPRT
deleted file mode 100644
index 7b0204e..0000000
Binary files a/mechanic/HEATSINK FOR A4988.SLDPRT and /dev/null differ
diff --git a/mechanic/Idler Pulley Plate.SLDPRT b/mechanic/Idler Pulley Plate.SLDPRT
deleted file mode 100644
index 145b944..0000000
Binary files a/mechanic/Idler Pulley Plate.SLDPRT and /dev/null differ
diff --git a/mechanic/LICENSE b/mechanic/LICENSE
deleted file mode 100644
index 671a7d9..0000000
--- a/mechanic/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018 guesswho461
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/mechanic/Linear Actuator End Mount.SLDPRT b/mechanic/Linear Actuator End Mount.SLDPRT
deleted file mode 100644
index 4fbb412..0000000
Binary files a/mechanic/Linear Actuator End Mount.SLDPRT and /dev/null differ
diff --git a/mechanic/Lock Collar 8mm.SLDPRT b/mechanic/Lock Collar 8mm.SLDPRT
deleted file mode 100644
index ed6a753..0000000
Binary files a/mechanic/Lock Collar 8mm.SLDPRT and /dev/null differ
diff --git a/mechanic/Low Profile Screw M5.SLDPRT b/mechanic/Low Profile Screw M5.SLDPRT
deleted file mode 100644
index a373e91..0000000
Binary files a/mechanic/Low Profile Screw M5.SLDPRT and /dev/null differ
diff --git a/mechanic/Motor Mount Plate Nema 17.SLDPRT b/mechanic/Motor Mount Plate Nema 17.SLDPRT
deleted file mode 100644
index cac5b25..0000000
Binary files a/mechanic/Motor Mount Plate Nema 17.SLDPRT and /dev/null differ
diff --git a/mechanic/Nema 17 Stepper Motor.SLDPRT b/mechanic/Nema 17 Stepper Motor.SLDPRT
deleted file mode 100644
index 79feabf..0000000
Binary files a/mechanic/Nema 17 Stepper Motor.SLDPRT and /dev/null differ
diff --git a/mechanic/Nylon Insert Lock Nut M3.SLDPRT b/mechanic/Nylon Insert Lock Nut M3.SLDPRT
deleted file mode 100644
index a5c4108..0000000
Binary files a/mechanic/Nylon Insert Lock Nut M3.SLDPRT and /dev/null differ
diff --git a/mechanic/Nylon Insert Lock Nut M5.SLDPRT b/mechanic/Nylon Insert Lock Nut M5.SLDPRT
deleted file mode 100644
index a47f772..0000000
Binary files a/mechanic/Nylon Insert Lock Nut M5.SLDPRT and /dev/null differ
diff --git a/mechanic/Nylon Spacer 0.125in.SLDPRT b/mechanic/Nylon Spacer 0.125in.SLDPRT
deleted file mode 100644
index 503e1a6..0000000
Binary files a/mechanic/Nylon Spacer 0.125in.SLDPRT and /dev/null differ
diff --git a/mechanic/PCB_LCD.SLDPRT b/mechanic/PCB_LCD.SLDPRT
deleted file mode 100644
index 0427610..0000000
Binary files a/mechanic/PCB_LCD.SLDPRT and /dev/null differ
diff --git a/mechanic/Precision Shim 10 x 5 x 1.SLDPRT b/mechanic/Precision Shim 10 x 5 x 1.SLDPRT
deleted file mode 100644
index a26592c..0000000
Binary files a/mechanic/Precision Shim 10 x 5 x 1.SLDPRT and /dev/null differ
diff --git a/mechanic/README.md b/mechanic/README.md
deleted file mode 100644
index 49b0abd..0000000
--- a/mechanic/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# cakeVending
\ No newline at end of file
diff --git a/mechanic/Self Tapping Screw.SLDPRT b/mechanic/Self Tapping Screw.SLDPRT
deleted file mode 100644
index ee34f7a..0000000
Binary files a/mechanic/Self Tapping Screw.SLDPRT and /dev/null differ
diff --git a/mechanic/Shim Washer 8mm.SLDPRT b/mechanic/Shim Washer 8mm.SLDPRT
deleted file mode 100644
index db6c12e..0000000
Binary files a/mechanic/Shim Washer 8mm.SLDPRT and /dev/null differ
diff --git a/mechanic/Smooth Idler Pulley Wheel.SLDPRT b/mechanic/Smooth Idler Pulley Wheel.SLDPRT
deleted file mode 100644
index 86ae84d..0000000
Binary files a/mechanic/Smooth Idler Pulley Wheel.SLDPRT and /dev/null differ
diff --git a/mechanic/Smooth Idler.SLDASM b/mechanic/Smooth Idler.SLDASM
deleted file mode 100644
index 98eef3a..0000000
Binary files a/mechanic/Smooth Idler.SLDASM and /dev/null differ
diff --git a/mechanic/Socket Head Cap Screw M3.SLDPRT b/mechanic/Socket Head Cap Screw M3.SLDPRT
deleted file mode 100644
index 27514a9..0000000
Binary files a/mechanic/Socket Head Cap Screw M3.SLDPRT and /dev/null differ
diff --git a/mechanic/Solid V Wheel.SLDPRT b/mechanic/Solid V Wheel.SLDPRT
deleted file mode 100644
index e31deda..0000000
Binary files a/mechanic/Solid V Wheel.SLDPRT and /dev/null differ
diff --git a/mechanic/Spacer Block 2.SLDPRT b/mechanic/Spacer Block 2.SLDPRT
deleted file mode 100644
index 6001ed9..0000000
Binary files a/mechanic/Spacer Block 2.SLDPRT and /dev/null differ
diff --git a/mechanic/Threaded Rod Plate Nema 17.SLDPRT b/mechanic/Threaded Rod Plate Nema 17.SLDPRT
deleted file mode 100644
index 26cd71c..0000000
Binary files a/mechanic/Threaded Rod Plate Nema 17.SLDPRT and /dev/null differ
diff --git a/mechanic/USER LIBRARY-MF-R500___ _________.SLDPRT b/mechanic/USER LIBRARY-MF-R500___ _________.SLDPRT
deleted file mode 100644
index d549d3a..0000000
Binary files a/mechanic/USER LIBRARY-MF-R500___ _________.SLDPRT and /dev/null differ
diff --git a/mechanic/V Slot 1.SLDBLK b/mechanic/V Slot 1.SLDBLK
deleted file mode 100644
index 487019b..0000000
Binary files a/mechanic/V Slot 1.SLDBLK and /dev/null differ
diff --git a/mechanic/V Slot 2.SLDBLK b/mechanic/V Slot 2.SLDBLK
deleted file mode 100644
index 75f8759..0000000
Binary files a/mechanic/V Slot 2.SLDBLK and /dev/null differ
diff --git a/mechanic/V-Slot 20x20x500 Linear Rail.SLDPRT b/mechanic/V-Slot 20x20x500 Linear Rail.SLDPRT
deleted file mode 100644
index 9013112..0000000
Binary files a/mechanic/V-Slot 20x20x500 Linear Rail.SLDPRT and /dev/null differ
diff --git a/mechanic/V-Slot 20x40x500 Linear Rail.SLDPRT b/mechanic/V-Slot 20x40x500 Linear Rail.SLDPRT
deleted file mode 100644
index 3e5657a..0000000
Binary files a/mechanic/V-Slot 20x40x500 Linear Rail.SLDPRT and /dev/null differ
diff --git a/mechanic/V-Slot 40x40x1000 Linear Rail.SLDPRT b/mechanic/V-Slot 40x40x1000 Linear Rail.SLDPRT
deleted file mode 100644
index 5b58039..0000000
Binary files a/mechanic/V-Slot 40x40x1000 Linear Rail.SLDPRT and /dev/null differ
diff --git a/mechanic/V-Slot 40x40x1500 Linear Rail.SLDPRT b/mechanic/V-Slot 40x40x1500 Linear Rail.SLDPRT
deleted file mode 100644
index b127b29..0000000
Binary files a/mechanic/V-Slot 40x40x1500 Linear Rail.SLDPRT and /dev/null differ
diff --git a/mechanic/V-Slot Gantry Plate 20-80mm 2.SLDPRT b/mechanic/V-Slot Gantry Plate 20-80mm 2.SLDPRT
deleted file mode 100644
index 2056cde..0000000
Binary files a/mechanic/V-Slot Gantry Plate 20-80mm 2.SLDPRT and /dev/null differ
diff --git a/mechanic/V-Slot Gantry Plate 20mm 2.SLDPRT b/mechanic/V-Slot Gantry Plate 20mm 2.SLDPRT
deleted file mode 100644
index 00cb8e5..0000000
Binary files a/mechanic/V-Slot Gantry Plate 20mm 2.SLDPRT and /dev/null differ
diff --git a/mechanic/X.SLDASM b/mechanic/X.SLDASM
deleted file mode 100644
index 88d08e2..0000000
Binary files a/mechanic/X.SLDASM and /dev/null differ
diff --git a/mechanic/Y.SLDASM b/mechanic/Y.SLDASM
deleted file mode 100644
index c5b7385..0000000
Binary files a/mechanic/Y.SLDASM and /dev/null differ
diff --git a/mechanic/Z.SLDASM b/mechanic/Z.SLDASM
deleted file mode 100644
index 18a95f4..0000000
Binary files a/mechanic/Z.SLDASM and /dev/null differ
diff --git a/mechanic/Z2.SLDASM b/mechanic/Z2.SLDASM
deleted file mode 100644
index 37dbbff..0000000
Binary files a/mechanic/Z2.SLDASM and /dev/null differ
diff --git a/mechanic/arm_control.SLDASM b/mechanic/arm_control.SLDASM
deleted file mode 100644
index fb70770..0000000
Binary files a/mechanic/arm_control.SLDASM and /dev/null differ
diff --git a/mechanic/arm_control_box.SLDPRT b/mechanic/arm_control_box.SLDPRT
deleted file mode 100644
index 01bfd75..0000000
Binary files a/mechanic/arm_control_box.SLDPRT and /dev/null differ
diff --git a/mechanic/box.SLDASM b/mechanic/box.SLDASM
deleted file mode 100644
index 8bf3fd2..0000000
Binary files a/mechanic/box.SLDASM and /dev/null differ
diff --git a/mechanic/frige.SLDPRT b/mechanic/frige.SLDPRT
deleted file mode 100644
index 96cf463..0000000
Binary files a/mechanic/frige.SLDPRT and /dev/null differ
diff --git a/mechanic/keg.SLDPRT b/mechanic/keg.SLDPRT
deleted file mode 100644
index d64530c..0000000
Binary files a/mechanic/keg.SLDPRT and /dev/null differ
diff --git a/mechanic/manipulator.SLDASM b/mechanic/manipulator.SLDASM
deleted file mode 100644
index a071d25..0000000
Binary files a/mechanic/manipulator.SLDASM and /dev/null differ
diff --git a/mechanic/manipulator2.SLDASM b/mechanic/manipulator2.SLDASM
deleted file mode 100644
index 4b8c0f2..0000000
Binary files a/mechanic/manipulator2.SLDASM and /dev/null differ
diff --git a/mechanic/mid plate.SLDASM b/mechanic/mid plate.SLDASM
deleted file mode 100644
index 2dcfba7..0000000
Binary files a/mechanic/mid plate.SLDASM and /dev/null differ
diff --git a/mechanic/oven.SLDPRT b/mechanic/oven.SLDPRT
deleted file mode 100644
index b784609..0000000
Binary files a/mechanic/oven.SLDPRT and /dev/null differ
diff --git a/mechanic/small plate.SLDASM b/mechanic/small plate.SLDASM
deleted file mode 100644
index 4930d69..0000000
Binary files a/mechanic/small plate.SLDASM and /dev/null differ
diff --git a/mechanic/small wheel.SLDASM b/mechanic/small wheel.SLDASM
deleted file mode 100644
index d0f5ac3..0000000
Binary files a/mechanic/small wheel.SLDASM and /dev/null differ
diff --git a/recipe/cpp/.vscode/settings.json b/recipe/cpp/.vscode/settings.json
new file mode 100644
index 0000000..9c4a20a
--- /dev/null
+++ b/recipe/cpp/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "C_Cpp.default.configurationProvider": "vector-of-bool.cmake-tools"
+}
\ No newline at end of file
diff --git a/recipe/cpp/CMakeLists.txt b/recipe/cpp/CMakeLists.txt
new file mode 100644
index 0000000..8785ec9
--- /dev/null
+++ b/recipe/cpp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
+project(recipeCppTest1)
+
+add_executable(recipeCppTest1 main.cpp)
diff --git a/recipe/cpp/main.cpp b/recipe/cpp/main.cpp
new file mode 100644
index 0000000..6dbf005
--- /dev/null
+++ b/recipe/cpp/main.cpp
@@ -0,0 +1,7 @@
+#include
+
+int main()
+{
+ printf("Hello, world\n");
+ return 0;
+}
\ No newline at end of file
diff --git a/recipe/cpp/sysprogs-rpi-win-toolchain.cmake b/recipe/cpp/sysprogs-rpi-win-toolchain.cmake
new file mode 100644
index 0000000..27a2456
--- /dev/null
+++ b/recipe/cpp/sysprogs-rpi-win-toolchain.cmake
@@ -0,0 +1,17 @@
+# this one is important
+SET(CMAKE_SYSTEM_NAME Linux)
+#this one not so much
+SET(CMAKE_SYSTEM_VERSION 1)
+
+# specify the cross compiler
+SET(CMAKE_C_COMPILER E:/SysGCC/raspberry/bin/arm-linux-gnueabihf-gcc.exe)
+SET(CMAKE_CXX_COMPILER E:/SysGCC/raspberry/bin/arm-linux-gnueabihf-g++.exe)
+
+# where is the target environment
+SET(CMAKE_FIND_ROOT_PATH E:/SysGCC/raspberry)
+
+# search for programs in the build host directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
\ No newline at end of file
diff --git a/recipe/node/TestRunOK_0407.js b/recipe/node/TestRunOK_0407.js
new file mode 100644
index 0000000..b9e90b4
--- /dev/null
+++ b/recipe/node/TestRunOK_0407.js
@@ -0,0 +1,812 @@
+//有料測試用
+const log4js = require("log4js");
+log4js.configure({
+ appenders: {
+ file: {
+ type: "dateFile",
+ filename: "log/recipe.log",
+ daysToKeep: 1,
+ pattern: ".mm",
+ },
+ out: {
+ type: "stdout",
+ },
+ },
+ categories: {
+ default: { appenders: ["file", "out"], level: "trace" },
+ },
+});
+const logger = log4js.getLogger("cake");
+
+const mqtt = require("mqtt");
+const delay = require("delay");
+const waitUntil = require("async-wait-until");
+
+const opt = {
+ port: 1883,
+ clientId: "recipeOriginal",
+};
+
+const waitRobotMotionDoneTimeout = 60000; //ms
+const waitOvenTimeout = 60000; //ms
+const waitBowloutTimeout = 60000; //ms
+const waitTakeBowlTimeout = 3000000; //ms
+
+let robotMotionDone = true;
+let ovenFlipTrue = false;
+let ovenFlipFalse = false;
+let ovenOpenTrue = false;
+let ovenOpenFalse = false;
+let bucketStopTrue = false;
+
+let latchArmStopTrue = false;
+let latchArmStopFalse = false;
+let latchCvtStopTrue = false;
+let latchCvtStopFalse = false;
+let latchSuckStopTrue = false;
+let latchSuckStopFalse = false;
+let latchBowlReadyTrue = false;
+let latchBowlReadyFalse = false;
+let latchGateOpenTrue = false;
+let latchGateOpenFalse = false;
+let latchFanOpenTrue = false;
+let latchFanOpenFalse = false;
+let cnt = 0;
+
+let strBowlCnt = "0";
+let strArmPos = "0";
+let strCvtPos = "0";
+let maxTimes = 200000; ///總需求物件數量
+
+let retry_waitBowlout = 0; ///物件未被取走次數累計
+let retry_TakeBowl = 0; ///物件取得失敗次數累計
+let cntTimes = 0; ///完成物件數
+
+let latchTakeBowl_Start = false;
+
+logger.trace(opt.clientId + " started");
+
+const client = mqtt.connect("mqtt://localhost", opt);
+
+client.on("connect", function () {
+ logger.trace("connect to broker OK");
+ client.subscribe("robot/status/stop");
+ client.subscribe("oven/status/flip");
+ client.subscribe("oven/status/open");
+ client.subscribe("bucket/status/stop");
+ client.subscribe("latch/status/arm/stop");
+ client.subscribe("latch/status/cvt/stop");
+ client.subscribe("latch/status/bowl/cnt");
+ client.subscribe("latch/status/bowl/ready");
+ client.subscribe("latch/status/arm/suck");
+ client.subscribe("latch/status/arm/release");
+ client.subscribe("latch/status/gate/open");
+ client.subscribe("latch/status/fan/open");
+ client.subscribe("latch/status/vibration");
+ client.subscribe("latch/status/arm/pos");
+ client.subscribe("latch/status/cvt/pos");
+});
+
+client.on("message", function (topic, msg) {
+ //logger.trace('topic ' + topic + ' - ' + msg);
+ if (topic === "robot/status/stop") {
+ if (msg.toString() === "true") {
+ robotMotionDone = true;
+ } else {
+ robotMotionDone = false;
+ }
+ } else if (topic === "oven/status/flip") {
+ if (msg.toString() === "true") {
+ ovenFlipTrue = true;
+ ovenFlipFalse = false;
+ } else {
+ ovenFlipTrue = false;
+ ovenFlipFalse = true;
+ }
+ } else if (topic === "oven/status/open") {
+ if (msg.toString() === "true") {
+ ovenOpenTrue = true;
+ ovenOpenFalse = false;
+ } else {
+ ovenOpenTrue = false;
+ ovenOpenFalse = true;
+ }
+ } else if (topic === "bucket/status/stop") {
+ if (msg.toString() === "true") {
+ bucketStopTrue = true;
+ bucketStopFalse = false;
+ } else {
+ bucketStopTrue = false;
+ bucketStopFalse = true;
+ }
+ } else if (topic === "latch/status/arm/stop") {
+ if (msg.toString() === "true") {
+ latchArmStopTrue = true;
+ latchArmStopFalse = false;
+ } else {
+ latchArmStopTrue = false;
+ latchArmStopFalse = true;
+ }
+ } else if (topic === "latch/status/cvt/stop") {
+ if (msg.toString() === "true") {
+ latchCvtStopTrue = true;
+ latchCvtStopFalse = false;
+ } else {
+ latchCvtStopTrue = false;
+ latchCvtStopFalse = true;
+ }
+ } else if (topic === "latch/status/arm/suck") {
+ if (msg.toString() === "true") {
+ latchSuckStopTrue = true;
+ latchSuckStopFalse = false;
+ } else {
+ latchSuckStopTrue = false;
+ latchSuckStopFalse = true;
+ }
+ } else if (topic === "latch/status/bowl/cnt") {
+ strBowlCnt = msg.toString();
+ } else if (topic === "latch/status/bowl/ready") {
+ if (msg.toString() === "true") {
+ latchBowlReadyTrue = true;
+ latchBowlReadyFalse = false;
+ //logger.trace('Ready:true');
+ } else {
+ latchBowlReadyTrue = false;
+ latchBowlReadyFalse = true;
+ //logger.trace('Ready:false');
+ }
+ } else if (topic === "latch/status/gate/open") {
+ if (msg.toString() === "true") {
+ latchGateOpenTrue = true;
+ latchGateOpenFalse = false;
+ //logger.trace('gateCmd:true');
+ } else {
+ latchGateOpenTrue = false;
+ latchGateOpenFalse = true;
+ //logger.trace('gateCmd:false');
+ }
+ } else if (topic === "latch/status/fan/open") {
+ if (msg.toString() === "true") {
+ latchFanOpenTrue = true;
+ latchFanOpenFalse = false;
+ //logger.trace('fanCmd:true');
+ } else {
+ latchFanOpenTrue = false;
+ latchFanOpenFalse = true;
+ //logger.trace('fanCmd:false');
+ }
+ } else if (topic === "latch/status/vibration") {
+ if (msg.toString() === "true") {
+ latchVibrationTrue = true;
+ latchVibrationFalse = false;
+ //logger.trace('vCmd:true');
+ } else {
+ latchVibrationTrue = false;
+ latchVibrationFalse = true;
+ //logger.trace('vCmd:false');
+ }
+ } else if (topic === "latch/status/arm/pos") {
+ strArmPos = msg.toString();
+ //logger.trace(strArmPos);
+ } else if (topic === "latch/status/cvt/pos") {
+ strCvtPos = msg.toString();
+ //logger.trace(strCvtPos);
+ } else if (topic === "latch/status/arm/release") {
+ if (msg.toString() === "true") {
+ latchArmReleaseTrue = true;
+ latchArmReleaseFalse = false;
+ } else {
+ latchArmReleaseTrue = false;
+ latchArmReleaseFalse = true;
+ }
+ }
+});
+
+async function waitRobotMotionDone(waitTime) {
+ await delay(waitTime);
+ robotMotionDone = false;
+ const result = await waitUntil(() => {
+ return robotMotionDone;
+ }, waitRobotMotionDoneTimeout);
+}
+
+async function waitOvenOpenTrue(waitTime) {
+ await delay(waitTime);
+ ovenOpenTrue = false;
+ const result = await waitUntil(() => {
+ return ovenOpenTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitOvenOpenFalse(waitTime) {
+ await delay(waitTime);
+ ovenOpenFalse = false;
+ const result = await waitUntil(() => {
+ return ovenOpenFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitOvenFlipTrue(waitTime) {
+ await delay(waitTime);
+ ovenFlipTrue = false;
+ const result = await waitUntil(() => {
+ return ovenFlipTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitOvenFlipFalse(waitTime) {
+ await delay(waitTime);
+ ovenFlipFalse = false;
+ const result = await waitUntil(() => {
+ return ovenFlipFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitbucketStopTrue(waitTime) {
+ await delay(waitTime);
+ bucketStopTrue = false;
+ const result = await waitUntil(() => {
+ return bucketStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitbucketStopFalse(waitTime) {
+ await delay(waitTime);
+ bucketStopFalse = false;
+ const result = await waitUntil(() => {
+ return bucketStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchArmStopTrue(waitTime) {
+ await delay(waitTime);
+ latchArmStopTrue = false;
+ const result = await waitUntil(() => {
+ return latchArmStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchArmStopFalse(waitTime) {
+ await delay(waitTime);
+ latchArmStopFalse = false;
+ const result = await waitUntil(() => {
+ return latchArmStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchCvtStopTrue(waitTime) {
+ await delay(waitTime);
+ latchCvtStopTrue = false;
+ const result = await waitUntil(() => {
+ return latchCvtStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchCvtStopFalse(waitTime) {
+ await delay(waitTime);
+ latchCvtStopFalse = false;
+ const result = await waitUntil(() => {
+ return latchCvtStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchSuckStopTrue(waitTime) {
+ await delay(waitTime);
+ latchSuckStopTrue = false;
+ const result = await waitUntil(() => {
+ return latchSuckStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchSuckStopFalse(waitTime) {
+ await delay(waitTime);
+ latchSuckStopFalse = false;
+ const result = await waitUntil(() => {
+ return latchSuckStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchGateOpenTrue(waitTime) {
+ await delay(waitTime);
+ latchGateOpenTrue = false;
+ const result = await waitUntil(() => {
+ //logger.trace(latchGateOpenTrue);
+ return latchGateOpenTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchGateOpenFalse(waitTime) {
+ await delay(waitTime);
+ latchGateOpenFalse = false;
+ const result = await waitUntil(() => {
+ //logger.trace(latchGateOpenFalse);
+ return latchGateOpenFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchFanOpenTrue(waitTime) {
+ await delay(waitTime);
+ latchFanOpenTrue = false;
+ const result = await waitUntil(() => {
+ //logger.trace(latchFanOpenTrue);
+ return latchFanOpenTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchFanOpenFalse(waitTime) {
+ await delay(waitTime);
+ latchFanOpenFalse = false;
+ const result = await waitUntil(() => {
+ return latchFanOpenFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitTakeBowl(waitTime) {
+ await delay(waitTime);
+ latchBowlReadyTrue = false;
+ const result = await waitUntil(() => {
+ return latchBowlReadyTrue;
+ }, waitTakeBowlTimeout);
+}
+
+async function waitBowlout(waitTime) {
+ await delay(waitTime);
+ latchBowlReadyFalse = false;
+ const result = await waitUntil(() => {
+ return latchBowlReadyFalse;
+ }, waitBowloutTimeout);
+}
+
+async function waitlatchTakeBowlStart(waitTime) {
+ await delay(waitTime);
+ //latchTakeBowl_Start = false;
+ const result = await waitUntil(() => {
+ return latchTakeBowl_Start;
+ }, waitTakeBowlTimeout);
+}
+
+async function waitlatchStockBowlStart(waitTime) {
+ await delay(waitTime);
+ //latchStockBowl_Start = false;
+ const result = await waitUntil(() => {
+ return latchStockBowl_Start;
+ }, waitRobotMotionDoneTimeout);
+}
+
+async function chkArmPos(pos) {
+ if (Number(pos) === Number(strArmPos)) return true;
+ else return false;
+}
+
+async function chkCvtPos(pos) {
+ if (Number(pos) === Number(strCvtPos)) return true;
+ else return false;
+}
+
+async function robotDropCake(waitTime) {
+ client.publish("robot/cmd/jog/x", "0");
+ client.publish("robot/cmd/jog/y", "-130");
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+}
+
+async function Unloading(waitTime) {
+ await waitTakeBowl();
+
+ ///開啟散熱風扇
+ client.publish("latch/cmd/fan/open", "true");
+ logger.trace("10");
+ await waitlatchFanOpenTrue(waitTime);
+
+ ///開啟物料閘門
+ client.publish("latch/cmd/gate/open", "true");
+ logger.trace("11");
+ await waitlatchGateOpenTrue(waitTime);
+ await delay(4000);
+ logger.trace("12");
+
+ client.publish("latch/cmd/gate/open", "false");
+ await waitlatchGateOpenFalse(waitTime);
+ await delay(1500);
+ logger.trace("13");
+
+ ///關閉散熱風扇
+ client.publish("latch/cmd/fan/open", "false");
+ await waitlatchFanOpenFalse(waitTime);
+ await delay(500);
+ logger.trace("14");
+
+ ///剩餘物件數量
+ logger.trace(strBowlCnt);
+
+ logger.trace("Stock Bowl Process finish!");
+}
+
+(async () => {
+ let waitTime = 0; ///預留cmd傳遞時間
+
+ while (true) {
+ latchTakeBowl_Start = true;
+
+ logger.trace("main script start!");
+
+ client.publish("robot/cmd/jog/vel", "300 ");
+ client.publish("bucket/cmd/jog/vel", "300");
+
+ client.publish("oven/cmd/open", "true");
+ logger.trace("oven first close");
+ await delay(1500);
+
+ client.publish("robot/cmd/jog/x", "240");
+ client.publish("robot/cmd/jog/y", "-15");
+ client.publish("robot/cmd/jog/z", "-110");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P1");
+
+ //client.publish('bucket/cmd/jog/vol', '99');
+ //await waitbucketStopTrue(waitTime);
+
+ client.publish("bucket/cmd/jog/vol", "30");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P1");
+
+ client.publish("robot/cmd/jog/y", "-61");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P2");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P2");
+
+ client.publish("robot/cmd/jog/y", "-107");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P3");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P3");
+
+ client.publish("robot/cmd/jog/y", "-153");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P4");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P4");
+
+ client.publish("robot/cmd/jog/y", "-199");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P5");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P5");
+
+ client.publish("robot/cmd/jog/y", "-245");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P6");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P6");
+
+ client.publish("bucket/cmd/jog/vol", "-10"); //suck back
+ await waitbucketStopTrue(waitTime);
+ logger.trace("pump suck back");
+
+ client.publish("robot/cmd/jog/x", "150");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to avoid point");
+
+ client.publish("robot/cmd/jog/x", "0");
+ client.publish("robot/cmd/jog/y", "0");
+ client.publish("robot/cmd/jog/z", "0");
+ logger.trace("robot go to 000");
+ //await waitRobotMotionDone();
+
+ //------開始烤蛋糕程序------
+
+ client.publish("oven/cmd/open", "false");
+ await waitOvenOpenFalse(waitTime);
+ logger.trace("oven close");
+
+ client.publish("oven/cmd/flip", "true");
+ await waitOvenFlipTrue();
+ logger.trace("oven flip true");
+
+ //await delay(75000); //bake 1 min 15s
+ await delay(1000);
+
+ client.publish("oven/cmd/flip", "false");
+ await waitOvenFlipFalse();
+ logger.trace("oven flip false");
+
+ //await delay(120000); //bake 2 min
+ await delay(1000);
+
+ // for(i=0;i<1;i++) //12
+ // {
+ // //one loop 3+5+3+5=16s
+ // client.publish('oven/cmd/flip', 'true');
+ // await waitOvenFlipTrue(waitTime);
+ // await delay(1000); //bake 5s
+
+ // client.publish('oven/cmd/flip', 'false');
+ // await waitOvenFlipFalse(waitTime);
+ // await delay(1000); ////bake 5s
+ // }
+
+ client.publish("robot/cmd/home/z", "true");
+ client.publish("robot/cmd/home/y", "true");
+ client.publish("robot/cmd/home/x", "true");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot go home");
+
+ client.publish("oven/cmd/open", "true");
+ logger.trace("oven open");
+ await delay(1500);
+
+ // //------開始夾蛋糕程序------
+ // //-----開始第一顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-20");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P1");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P1");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P1");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第一顆放料----------
+
+ // //-----開始第二顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-66");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P2");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P2");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P2");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第二顆放料----------
+
+ // //-----開始第三顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-113");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P3");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P3");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P3");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第三顆放料----------
+
+ // //-----開始第四顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-158");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P4");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P4");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P4");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第四顆放料----------
+
+ // //-----開始第五顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-204");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P5");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P5");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P5");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第五顆放料----------
+
+ // //-----開始第六顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-250");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P6");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P6");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P6");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第六顆放料----------
+
+ client.publish("robot/cmd/jog/x", "0");
+ client.publish("robot/cmd/jog/y", "0");
+ client.publish("robot/cmd/jog/z", "0");
+ logger.trace("robot go to 000");
+
+ client.publish("oven/cmd/open", "false");
+ await waitOvenOpenFalse(waitTime);
+ logger.trace("oven close");
+
+ await Unloading(waitTime);
+ logger.trace("drop cake to bowl");
+
+ client.publish("robot/cmd/home/z", "true");
+ client.publish("robot/cmd/home/y", "true");
+ client.publish("robot/cmd/home/x", "true");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot go home");
+
+ ///確認物件是否被取走
+ ///await waitBowlout();
+
+ logger.trace("Process finish!!!!!!!!!!!!!");
+ }
+})();
+
+(async () => {
+ ///取碗part
+ let waitTime = 100; ///預留cmd傳遞時間
+ logger.trace("sub script start!");
+
+ ///設定arm移動速度
+ client.publish("latch/cmd/arm/vel", "40"); //vel:23 -> delay:200
+ await delay(waitTime);
+
+ ///設定cv移動速度
+ client.publish("latch/cmd/cvt/vel", "130"); //vel:125 -> delay:800
+ await delay(waitTime);
+
+ latchTakeBowl_Start = true;
+
+ //do {
+ await waitlatchTakeBowlStart();
+
+ retry_TakeBowl = 0;
+
+ do {
+ logger.trace("01");
+ ///cv移動到取物件位置
+ client.publish("latch/cmd/cvt/pos", "-202");
+ await delay(2000);
+ await waitlatchCvtStopTrue();
+ logger.trace("02");
+
+ ///arm上伸到取物件位置
+ switch (
+ retry_TakeBowl % 3 ///調整arm上伸到取物件位置
+ ) {
+ case 0:
+ client.publish("latch/cmd/arm/pos", "110");
+ break;
+ case 1:
+ client.publish("latch/cmd/arm/pos", "112");
+ break;
+ case 2:
+ client.publish("latch/cmd/arm/pos", "115");
+ break;
+ }
+
+ //await delay(waitTime);
+ await delay(3000);
+ await waitlatchArmStopTrue();
+ logger.trace("03");
+
+ ///吸取物件
+ client.publish("latch/cmd/arm/suck", "true");
+ await delay(300);
+ //await delay(waitTime);
+ await waitlatchSuckStopTrue();
+ logger.trace("04");
+
+ ///arm下降到cv平台位置
+ client.publish("latch/cmd/arm/pos", "22");
+ await delay(2000);
+ //await delay(waitTime);
+ await waitlatchArmStopTrue();
+ logger.trace("05");
+
+ ///釋放物件
+ client.publish("latch/cmd/arm/suck", "false");
+ await delay(4000);
+ //await delay(waitTime);
+ await waitlatchSuckStopFalse();
+ logger.trace("06");
+
+ ///arm下降到原點位置
+ client.publish("latch/cmd/arm/pos", "0");
+ await delay(1500);
+ //await delay(waitTime);
+ await waitlatchArmStopTrue();
+ logger.trace("07");
+
+ ///cv移動到放物料位置
+ client.publish("latch/cmd/cvt/pos", "0");
+ await delay(2000);
+ //await delay(waitTime);
+ await waitlatchCvtStopTrue();
+ logger.trace("08");
+
+ await delay(500);
+ retry_TakeBowl++;
+ ///確認是否取得物件
+ } while (latchBowlReadyTrue == false && retry_TakeBowl < 10);
+
+ if (retry_TakeBowl >= 10) {
+ ///Err:多次物件取得失敗
+ logger.trace("Take Bowl Error!");
+ break;
+ }
+
+ latchTakeBowl_Start = false;
+ //} while (cntTimes < maxTimes);
+
+ logger.trace("Take Bowl Process finish!");
+})();
diff --git a/recipe/node/TestRunOK_0409.js b/recipe/node/TestRunOK_0409.js
new file mode 100644
index 0000000..c6fb6f5
--- /dev/null
+++ b/recipe/node/TestRunOK_0409.js
@@ -0,0 +1,822 @@
+//無料空跑測試用
+
+const log4js = require("log4js");
+log4js.configure({
+ appenders: {
+ file: {
+ type: "dateFile",
+ filename: "log/recipe.log",
+ maxLogSize: 20000000, // 20 MB
+ backups: 5,
+ category: "normal",
+ },
+ out: {
+ type: "stdout",
+ },
+ },
+ categories: {
+ default: { appenders: ["file", "out"], level: "trace" },
+ },
+});
+const logger = log4js.getLogger("cake");
+
+const mqtt = require("mqtt");
+const delay = require("delay");
+const waitUntil = require("async-wait-until");
+
+const opt = {
+ port: 1883,
+ clientId: "recipeOriginal",
+};
+
+const waitRobotMotionDoneTimeout = 60000; //ms
+const waitOvenTimeout = 60000; //ms
+const waitBowloutTimeout = 60000; //ms
+const waitTakeBowlTimeout = 3000000; //ms
+
+let robotMotionDone = true;
+let ovenFlipTrue = false;
+let ovenFlipFalse = false;
+let ovenOpenTrue = false;
+let ovenOpenFalse = false;
+let bucketStopTrue = false;
+
+let latchArmStopTrue = false;
+let latchArmStopFalse = false;
+let latchCvtStopTrue = false;
+let latchCvtStopFalse = false;
+let latchSuckStopTrue = false;
+let latchSuckStopFalse = false;
+let latchBowlReadyTrue = false;
+let latchBowlReadyFalse = false;
+let latchGateOpenTrue = false;
+let latchGateOpenFalse = false;
+let latchFanOpenTrue = false;
+let latchFanOpenFalse = false;
+let cnt = 0;
+
+let strBowlCnt = "0";
+let strArmPos = "0";
+let strCvtPos = "0";
+let maxTimes = 1; ///總需求物件數量
+
+let retry_waitBowlout = 0; ///物件未被取走次數累計
+let retry_TakeBowl = 0; ///物件取得失敗次數累計
+let cntTimes = 0; ///完成物件數
+
+let latchTakeBowl_Start = false;
+
+logger.trace(opt.clientId + " started");
+
+const client = mqtt.connect("mqtt://localhost", opt);
+
+client.on("connect", function () {
+ logger.trace("connect to broker OK");
+ client.subscribe("robot/status/stop");
+ client.subscribe("oven/status/flip");
+ client.subscribe("oven/status/open");
+ client.subscribe("bucket/status/stop");
+ client.subscribe("latch/status/arm/stop");
+ client.subscribe("latch/status/cvt/stop");
+ client.subscribe("latch/status/bowl/cnt");
+ client.subscribe("latch/status/bowl/ready");
+ client.subscribe("latch/status/arm/suck");
+ client.subscribe("latch/status/arm/release");
+ client.subscribe("latch/status/gate/open");
+ client.subscribe("latch/status/fan/open");
+ client.subscribe("latch/status/vibration");
+ client.subscribe("latch/status/arm/pos");
+ client.subscribe("latch/status/cvt/pos");
+});
+
+client.on("message", function (topic, msg) {
+ //logger.trace('topic ' + topic + ' - ' + msg);
+ if (topic === "robot/status/stop") {
+ if (msg.toString() === "true") {
+ robotMotionDone = true;
+ } else {
+ robotMotionDone = false;
+ }
+ } else if (topic === "oven/status/flip") {
+ if (msg.toString() === "true") {
+ ovenFlipTrue = true;
+ ovenFlipFalse = false;
+ } else {
+ ovenFlipTrue = false;
+ ovenFlipFalse = true;
+ }
+ } else if (topic === "oven/status/open") {
+ if (msg.toString() === "true") {
+ ovenOpenTrue = true;
+ ovenOpenFalse = false;
+ } else {
+ ovenOpenTrue = false;
+ ovenOpenFalse = true;
+ }
+ } else if (topic === "bucket/status/stop") {
+ if (msg.toString() === "true") {
+ bucketStopTrue = true;
+ bucketStopFalse = false;
+ } else {
+ bucketStopTrue = false;
+ bucketStopFalse = true;
+ }
+ } else if (topic === "latch/status/arm/stop") {
+ if (msg.toString() === "true") {
+ latchArmStopTrue = true;
+ latchArmStopFalse = false;
+ } else {
+ latchArmStopTrue = false;
+ latchArmStopFalse = true;
+ }
+ } else if (topic === "latch/status/cvt/stop") {
+ if (msg.toString() === "true") {
+ latchCvtStopTrue = true;
+ latchCvtStopFalse = false;
+ } else {
+ latchCvtStopTrue = false;
+ latchCvtStopFalse = true;
+ }
+ } else if (topic === "latch/status/arm/suck") {
+ if (msg.toString() === "true") {
+ latchSuckStopTrue = true;
+ latchSuckStopFalse = false;
+ } else {
+ latchSuckStopTrue = false;
+ latchSuckStopFalse = true;
+ }
+ } else if (topic === "latch/status/bowl/cnt") {
+ strBowlCnt = msg.toString();
+ } else if (topic === "latch/status/bowl/ready") {
+ if (msg.toString() === "true") {
+ latchBowlReadyTrue = true;
+ latchBowlReadyFalse = false;
+ //logger.trace('Ready:true');
+ } else {
+ latchBowlReadyTrue = false;
+ latchBowlReadyFalse = true;
+ //logger.trace('Ready:false');
+ }
+ } else if (topic === "latch/status/gate/open") {
+ if (msg.toString() === "true") {
+ latchGateOpenTrue = true;
+ latchGateOpenFalse = false;
+ //logger.trace('gateCmd:true');
+ } else {
+ latchGateOpenTrue = false;
+ latchGateOpenFalse = true;
+ //logger.trace('gateCmd:false');
+ }
+ } else if (topic === "latch/status/fan/open") {
+ if (msg.toString() === "true") {
+ latchFanOpenTrue = true;
+ latchFanOpenFalse = false;
+ //logger.trace('fanCmd:true');
+ } else {
+ latchFanOpenTrue = false;
+ latchFanOpenFalse = true;
+ //logger.trace('fanCmd:false');
+ }
+ } else if (topic === "latch/status/vibration") {
+ if (msg.toString() === "true") {
+ latchVibrationTrue = true;
+ latchVibrationFalse = false;
+ //logger.trace('vCmd:true');
+ } else {
+ latchVibrationTrue = false;
+ latchVibrationFalse = true;
+ //logger.trace('vCmd:false');
+ }
+ } else if (topic === "latch/status/arm/pos") {
+ strArmPos = msg.toString();
+ //logger.trace(strArmPos);
+ } else if (topic === "latch/status/cvt/pos") {
+ strCvtPos = msg.toString();
+ //logger.trace(strCvtPos);
+ } else if (topic === "latch/status/arm/release") {
+ if (msg.toString() === "true") {
+ latchArmReleaseTrue = true;
+ latchArmReleaseFalse = false;
+ } else {
+ latchArmReleaseTrue = false;
+ latchArmReleaseFalse = true;
+ }
+ }
+});
+
+async function waitRobotMotionDone(waitTime) {
+ await delay(waitTime);
+ robotMotionDone = false;
+ const result = await waitUntil(() => {
+ return robotMotionDone;
+ }, waitRobotMotionDoneTimeout);
+}
+
+async function waitOvenOpenTrue(waitTime) {
+ await delay(waitTime);
+ ovenOpenTrue = false;
+ const result = await waitUntil(() => {
+ return ovenOpenTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitOvenOpenFalse(waitTime) {
+ await delay(waitTime);
+ ovenOpenFalse = false;
+ const result = await waitUntil(() => {
+ return ovenOpenFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitOvenFlipTrue(waitTime) {
+ await delay(waitTime);
+ ovenFlipTrue = false;
+ const result = await waitUntil(() => {
+ return ovenFlipTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitOvenFlipFalse(waitTime) {
+ await delay(waitTime);
+ ovenFlipFalse = false;
+ const result = await waitUntil(() => {
+ return ovenFlipFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitbucketStopTrue(waitTime) {
+ await delay(waitTime);
+ bucketStopTrue = false;
+ const result = await waitUntil(() => {
+ return bucketStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitbucketStopFalse(waitTime) {
+ await delay(waitTime);
+ bucketStopFalse = false;
+ const result = await waitUntil(() => {
+ return bucketStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchArmStopTrue(waitTime) {
+ await delay(waitTime);
+ latchArmStopTrue = false;
+ const result = await waitUntil(() => {
+ return latchArmStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchArmStopFalse(waitTime) {
+ await delay(waitTime);
+ latchArmStopFalse = false;
+ const result = await waitUntil(() => {
+ return latchArmStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchCvtStopTrue(waitTime) {
+ await delay(waitTime);
+ latchCvtStopTrue = false;
+ const result = await waitUntil(() => {
+ return latchCvtStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchCvtStopFalse(waitTime) {
+ await delay(waitTime);
+ latchCvtStopFalse = false;
+ const result = await waitUntil(() => {
+ return latchCvtStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchSuckStopTrue(waitTime) {
+ await delay(waitTime);
+ latchSuckStopTrue = false;
+ const result = await waitUntil(() => {
+ return latchSuckStopTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchSuckStopFalse(waitTime) {
+ await delay(waitTime);
+ latchSuckStopFalse = false;
+ const result = await waitUntil(() => {
+ return latchSuckStopFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchGateOpenTrue(waitTime) {
+ await delay(waitTime);
+ latchGateOpenTrue = false;
+ const result = await waitUntil(() => {
+ //logger.trace(latchGateOpenTrue);
+ return latchGateOpenTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchGateOpenFalse(waitTime) {
+ await delay(waitTime);
+ latchGateOpenFalse = false;
+ const result = await waitUntil(() => {
+ //logger.trace(latchGateOpenFalse);
+ return latchGateOpenFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchFanOpenTrue(waitTime) {
+ await delay(waitTime);
+ latchFanOpenTrue = false;
+ const result = await waitUntil(() => {
+ //logger.trace(latchFanOpenTrue);
+ return latchFanOpenTrue;
+ }, waitOvenTimeout);
+}
+
+async function waitlatchFanOpenFalse(waitTime) {
+ await delay(waitTime);
+ latchFanOpenFalse = false;
+ const result = await waitUntil(() => {
+ return latchFanOpenFalse;
+ }, waitOvenTimeout);
+}
+
+async function waitTakeBowl(waitTime) {
+ await delay(waitTime);
+ latchBowlReadyTrue = false;
+ const result = await waitUntil(() => {
+ return latchBowlReadyTrue;
+ }, waitTakeBowlTimeout);
+}
+
+async function waitBowlout(waitTime) {
+ await delay(waitTime);
+ latchBowlReadyFalse = false;
+ const result = await waitUntil(() => {
+ return latchBowlReadyFalse;
+ }, waitBowloutTimeout);
+}
+
+async function waitlatchTakeBowlStart(waitTime) {
+ await delay(waitTime);
+ //latchTakeBowl_Start = false;
+ const result = await waitUntil(() => {
+ return latchTakeBowl_Start;
+ }, waitTakeBowlTimeout);
+}
+
+async function waitlatchStockBowlStart(waitTime) {
+ await delay(waitTime);
+ //latchStockBowl_Start = false;
+ const result = await waitUntil(() => {
+ return latchStockBowl_Start;
+ }, waitRobotMotionDoneTimeout);
+}
+
+async function chkArmPos(pos) {
+ if (Number(pos) === Number(strArmPos)) return true;
+ else return false;
+}
+
+async function chkCvtPos(pos) {
+ if (Number(pos) === Number(strCvtPos)) return true;
+ else return false;
+}
+
+async function robotDropCake(waitTime) {
+ client.publish("robot/cmd/jog/x", "0");
+ client.publish("robot/cmd/jog/y", "-130");
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+}
+
+async function Unloading(waitTime) {
+ await waitTakeBowl();
+
+ ///開啟散熱風扇
+ client.publish("latch/cmd/fan/open", "true");
+ logger.trace("10");
+ await waitlatchFanOpenTrue(waitTime);
+
+ ///開啟物料閘門
+ client.publish("latch/cmd/gate/open", "true");
+ logger.trace("11");
+ await waitlatchGateOpenTrue(waitTime);
+ await delay(4000);
+ logger.trace("12");
+
+ client.publish("latch/cmd/gate/open", "false");
+ await waitlatchGateOpenFalse(waitTime);
+ await delay(1500);
+ logger.trace("13");
+
+ ///關閉散熱風扇
+ client.publish("latch/cmd/fan/open", "false");
+ await waitlatchFanOpenFalse(waitTime);
+ await delay(500);
+ logger.trace("14");
+
+ ///剩餘物件數量
+ logger.trace(strBowlCnt);
+
+ logger.trace("Stock Bowl Process finish!");
+}
+
+(async () => {
+ let waitTime = 50; ///預留cmd傳遞時間
+
+ //while (true) {
+ latchTakeBowl_Start = true;
+
+ logger.trace("main script start!");
+
+ client.publish("robot/cmd/jog/vel", "300 ");
+ client.publish("bucket/cmd/jog/vel", "300");
+
+ client.publish("oven/cmd/open", "true");
+ logger.trace("oven first close");
+ await delay(1500);
+
+ client.publish("robot/cmd/jog/x", "240");
+ client.publish("robot/cmd/jog/y", "-15");
+ client.publish("robot/cmd/jog/z", "-110");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P1");
+
+ //client.publish('bucket/cmd/jog/vol', '99');
+ //await waitbucketStopTrue(waitTime);
+
+ client.publish("bucket/cmd/jog/vol", "30");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P1");
+
+ client.publish("robot/cmd/jog/y", "-61");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P2");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P2");
+
+ client.publish("robot/cmd/jog/y", "-107");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P3");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P3");
+
+ client.publish("robot/cmd/jog/y", "-153");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P4");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P4");
+
+ client.publish("robot/cmd/jog/y", "-199");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P5");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P5");
+
+ client.publish("robot/cmd/jog/y", "-245");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move to P6");
+
+ client.publish("bucket/cmd/jog/vol", "33");
+ await waitbucketStopTrue(waitTime);
+ logger.trace("Spit to P6");
+
+ client.publish("bucket/cmd/jog/vol", "-10"); //suck back
+ await waitbucketStopTrue(waitTime);
+ logger.trace("pump suck back");
+
+ client.publish("robot/cmd/jog/x", "150");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to avoid point");
+
+ client.publish("robot/cmd/jog/x", "0");
+ client.publish("robot/cmd/jog/y", "0");
+ client.publish("robot/cmd/jog/z", "0");
+ logger.trace("robot go to 000");
+ //await waitRobotMotionDone();
+
+ //------開始烤蛋糕程序------
+
+ client.publish("oven/cmd/open", "false");
+ await waitOvenOpenFalse(waitTime);
+ logger.trace("oven close");
+
+ client.publish("oven/cmd/flip", "true");
+ await waitOvenFlipTrue();
+ logger.trace("oven flip true");
+
+ //await delay(75000); //bake 1 min 15s
+ await delay(1000);
+
+ client.publish("oven/cmd/flip", "false");
+ await waitOvenFlipFalse();
+ logger.trace("oven flip false");
+
+ //await delay(120000); //bake 2 min
+ await delay(1000);
+
+ // for(i=0;i<1;i++) //12
+ // {
+ // //one loop 3+5+3+5=16s
+ // client.publish('oven/cmd/flip', 'true');
+ // await waitOvenFlipTrue(waitTime);
+ // await delay(1000); //bake 5s
+
+ // client.publish('oven/cmd/flip', 'false');
+ // await waitOvenFlipFalse(waitTime);
+ // await delay(1000); ////bake 5s
+ // }
+
+ client.publish("robot/cmd/home/z", "true");
+ client.publish("robot/cmd/home/y", "true");
+ client.publish("robot/cmd/home/x", "true");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot go home");
+
+ client.publish("oven/cmd/open", "true");
+ logger.trace("oven open");
+ await delay(1500);
+
+ // //------開始夾蛋糕程序------
+ // //-----開始第一顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-20");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P1");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P1");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P1");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第一顆放料----------
+
+ // //-----開始第二顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-66");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P2");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P2");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P2");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第二顆放料----------
+
+ // //-----開始第三顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-113");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P3");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P3");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P3");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第三顆放料----------
+
+ // //-----開始第四顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-158");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P4");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P4");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P4");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第四顆放料----------
+
+ // //-----開始第五顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-204");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P5");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P5");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P5");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第五顆放料----------
+
+ // //-----開始第六顆放料----------
+ client.publish("robot/cmd/jog/x", "210");
+ client.publish("robot/cmd/jog/y", "-250");
+ client.publish("robot/cmd/jog/z", "-105");
+ client.publish("robot/cmd/jog/fork", "0"); //gripper OPEN
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot to Upper P6");
+
+ // //P7-1下 夾起
+ //client.publish('robot/cmd/jog/z', '-105');
+ client.publish("robot/cmd/jog/fork", "50"); //gripper CLOSE
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot grip at P6");
+
+ // //P7-2上 夾起
+ client.publish("robot/cmd/jog/z", "-70");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot move up at P6");
+
+ await robotDropCake(waitTime);
+ logger.trace("robot Drop Cake");
+ // //-----完成第六顆放料----------
+
+ client.publish("robot/cmd/jog/x", "0");
+ client.publish("robot/cmd/jog/y", "0");
+ client.publish("robot/cmd/jog/z", "0");
+ logger.trace("robot go to 000");
+
+ client.publish("oven/cmd/open", "false");
+ await waitOvenOpenFalse(waitTime);
+ logger.trace("oven close");
+
+ await Unloading(waitTime);
+ logger.trace("drop cake to bowl");
+
+ client.publish("robot/cmd/home/z", "true");
+ client.publish("robot/cmd/home/y", "true");
+ client.publish("robot/cmd/home/x", "true");
+ await waitRobotMotionDone(waitTime);
+ logger.trace("robot go home");
+
+ ///確認物件是否被取走
+ ///await waitBowlout();
+
+ logger.trace("Process finish!!!!!!!!!!!!!");
+ client.end();
+ //}
+})();
+
+(async () => {
+ ///取碗part
+ let waitTime = 100; ///預留cmd傳遞時間
+ logger.trace("sub script start!");
+
+ ///設定arm移動速度
+ client.publish("latch/cmd/arm/vel", "40"); //vel:23 -> delay:200
+ await delay(waitTime);
+
+ ///設定cv移動速度
+ client.publish("latch/cmd/cvt/vel", "130"); //vel:125 -> delay:800
+ await delay(waitTime);
+
+ latchTakeBowl_Start = true;
+
+ do {
+ await waitlatchTakeBowlStart();
+
+ retry_TakeBowl = 0;
+
+ do {
+ logger.trace("01");
+ ///cv移動到取物件位置
+ client.publish("latch/cmd/cvt/pos", "-202");
+ await delay(2000);
+ await waitlatchCvtStopTrue();
+ logger.trace("02");
+
+ ///arm上伸到取物件位置
+ switch (
+ retry_TakeBowl % 3 ///調整arm上伸到取物件位置
+ ) {
+ case 0:
+ client.publish("latch/cmd/arm/pos", "110");
+ break;
+ case 1:
+ client.publish("latch/cmd/arm/pos", "112");
+ break;
+ case 2:
+ client.publish("latch/cmd/arm/pos", "115");
+ break;
+ }
+
+ //await delay(waitTime);
+ await delay(3000);
+ await waitlatchArmStopTrue();
+ logger.trace("03");
+
+ ///吸取物件
+ client.publish("latch/cmd/arm/suck", "true");
+ await delay(300);
+ //await delay(waitTime);
+ await waitlatchSuckStopTrue();
+ logger.trace("04");
+
+ ///arm下降到cv平台位置
+ client.publish("latch/cmd/arm/pos", "22");
+ await delay(2000);
+ //await delay(waitTime);
+ await waitlatchArmStopTrue();
+ logger.trace("05");
+
+ ///釋放物件
+ client.publish("latch/cmd/arm/suck", "false");
+ await delay(4000);
+ //await delay(waitTime);
+ await waitlatchSuckStopFalse();
+ logger.trace("06");
+
+ ///arm下降到原點位置
+ client.publish("latch/cmd/arm/pos", "0");
+ await delay(1500);
+ //await delay(waitTime);
+ await waitlatchArmStopTrue();
+ logger.trace("07");
+
+ ///cv移動到放物料位置
+ client.publish("latch/cmd/cvt/pos", "0");
+ await delay(2000);
+ //await delay(waitTime);
+ await waitlatchCvtStopTrue();
+ logger.trace("08");
+
+ await delay(500);
+ retry_TakeBowl++;
+ ///確認是否取得物件
+ logger.trace("latchBowlReadyTrue: " + latchBowlReadyTrue);
+ logger.trace("retry_TakeBowl: " + retry_TakeBowl);
+ } while (latchBowlReadyTrue == false && retry_TakeBowl < 10);
+
+ if (retry_TakeBowl >= 10) {
+ ///Err:多次物件取得失敗
+ logger.trace("Take Bowl Error!");
+ break;
+ }
+
+ logger.trace("before latchTakeBowl_Start");
+
+ latchTakeBowl_Start = false;
+ cntTimes = cntTimes + 1;
+ } while (cntTimes < maxTimes);
+
+ logger.trace("cntTimes: " + cntTimes);
+
+ logger.trace("Take Bowl Process finish!");
+})();
diff --git a/recipes/original.js b/recipe/node/original.js
similarity index 100%
rename from recipes/original.js
rename to recipe/node/original.js
diff --git a/recipes/package.json b/recipe/node/package.json
similarity index 69%
rename from recipes/package.json
rename to recipe/node/package.json
index e4e2ba2..5ee89dd 100644
--- a/recipes/package.json
+++ b/recipe/node/package.json
@@ -4,16 +4,15 @@
"description": "",
"main": "original.js",
"scripts": {
- "start": "node test123.js",
- "pkg": "pkg original.js -o original -t node8-linux-armv7"
+ "start": "node test123.js"
},
- "bin": "original.js",
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {
"async-wait-until": "^1.2.4",
"delay": "^4.3.0",
+ "log4js": "^6.1.2",
"mqtt": "^3.0.0"
}
}
diff --git a/recipe/node/test.js b/recipe/node/test.js
new file mode 100644
index 0000000..89a36dd
--- /dev/null
+++ b/recipe/node/test.js
@@ -0,0 +1,38 @@
+const log4js = require('log4js');
+
+log4js.configure(
+ {
+ appenders: {
+ file: {
+ type: 'dateFile', filename: 'log/recipe.log', daysToKeep: 1, pattern: '.mm'
+ },
+ out: {
+ type: 'stdout'
+ }
+ },
+ categories: {
+ default: { appenders: ['file', 'out'], level: 'trace' }
+ }
+ }
+);
+
+const logger = log4js.getLogger('cake');
+
+let cnt = 0;
+let cnt1 = 0;
+
+(async () => {
+ do {
+ logger.trace('123');
+ cnt1 = cnt1 + 1;
+ } while(cnt1 < 5)
+})();
+
+(async () => {
+ do {
+ logger.trace('456');
+ cnt = cnt + 1;
+ } while(cnt < 5)
+})();
+
+logger.trace('end');
diff --git a/recipes/test123.js b/recipe/node/test123.js
similarity index 100%
rename from recipes/test123.js
rename to recipe/node/test123.js
diff --git a/recipes/test456.js b/recipe/node/test456.js
similarity index 100%
rename from recipes/test456.js
rename to recipe/node/test456.js
diff --git a/recipe/py/.vscode/settings.json b/recipe/py/.vscode/settings.json
new file mode 100644
index 0000000..21f07a0
--- /dev/null
+++ b/recipe/py/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "python.pythonPath": "/usr/bin/python2.7",
+ "python.linting.pylintEnabled": true,
+ "python.linting.enabled": true
+}
\ No newline at end of file
diff --git a/recipe/py/test.py b/recipe/py/test.py
new file mode 100644
index 0000000..4947cb8
--- /dev/null
+++ b/recipe/py/test.py
@@ -0,0 +1,544 @@
+import paho.mqtt.client as mqtt
+import signal
+import time
+import threading
+import logging
+from datetime import datetime
+
+
+class machineStatus:
+ robotMotionDone = True
+ ovenFlipTrue = False
+ ovenFlipFalse = False
+ ovenOpenTrue = False
+ ovenOpenFalse = False
+ bucketStopTrue = False
+ latchArmStopTrue = False
+ latchArmStopFalse = False
+ latchCvtStopTrue = False
+ latchCvtStopFalse = False
+ latchSuckStopTrue = False
+ latchSuckStopFalse = False
+ latchBowlReadyTrue = False
+ latchBowlReadyFalse = False
+ latchGateOpenTrue = False
+ latchGateOpenFalse = False
+ latchFanOpenTrue = False
+ latchFanOpenFalse = False
+ strBowlCnt = "0"
+ strArmPos = "0"
+ strCvtPos = "0"
+
+
+macst = machineStatus()
+looping = False
+mqttc = None
+latchTakeBowl_Start = False
+
+# def on_publish(mqttc, obj, mid):
+# logger.debug("mid: " + str(mid))
+# pass
+
+
+# def on_subscribe(mqttc, obj, mid, granted_qos):
+# logger.debug("Subscribed: " + str(mid) + " " + str(granted_qos))
+
+
+# def on_log(mqttc, obj, level, string):
+# logger.debug(string)
+
+def stop_all(*args):
+ global looping
+ looping = False
+
+
+def on_connect(mqttc, obj, flags, rc):
+ logger.warning('broker connected')
+ mqttc.subscribe('robot/status/stop')
+ mqttc.subscribe('oven/status/flip')
+ mqttc.subscribe('oven/status/open')
+ mqttc.subscribe('bucket/status/stop')
+ mqttc.subscribe('latch/status/arm/stop')
+ mqttc.subscribe('latch/status/cvt/stop')
+ mqttc.subscribe('latch/status/bowl/cnt')
+ mqttc.subscribe('latch/status/bowl/ready')
+ mqttc.subscribe('latch/status/arm/suck')
+ mqttc.subscribe('latch/status/arm/release')
+ mqttc.subscribe('latch/status/gate/open')
+ mqttc.subscribe('latch/status/fan/open')
+ mqttc.subscribe('latch/status/vibration')
+ mqttc.subscribe('latch/status/arm/pos')
+ mqttc.subscribe('latch/status/cvt/pos')
+
+
+def on_message(mqttc, obj, msg):
+ global macst
+ logger.debug(msg.topic + ": " + str(msg.payload))
+ if msg.topic == "robot/status/stop":
+ if str(msg.payload) == "true":
+ macst.robotMotionDone = True
+ else:
+ macst.robotMotionDone = False
+ elif msg.topic == "oven/status/flip":
+ if str(msg.payload) == "true":
+ macst.ovenFlipTrue = True
+ macst.ovenFlipFalse = False
+ else:
+ macst.ovenFlipTrue = False
+ macst.ovenFlipFalse = True
+ elif msg.topic == "oven/status/open":
+ if str(msg.payload) == "true":
+ macst.ovenOpenTrue = True
+ macst.ovenOpenFalse = False
+ else:
+ macst.ovenOpenTrue = False
+ macst.ovenOpenFalse = True
+ elif msg.topic == "bucket/status/stop":
+ if str(msg.payload) == "true":
+ macst.bucketStopTrue = True
+ macst.bucketStopFalse = False
+ else:
+ macst.bucketStopTrue = False
+ macst.bucketStopFalse = True
+ elif msg.topic == "latch/status/arm/stop":
+ if str(msg.payload) == "true":
+ macst.latchArmStopTrue = True
+ macst.latchArmStopFalse = False
+ else:
+ macst.latchArmStopTrue = False
+ macst.latchArmStopFalse = True
+ elif msg.topic == "latch/status/cvt/stop":
+ if str(msg.payload) == "true":
+ macst.latchCvtStopTrue = True
+ macst.latchCvtStopFalse = False
+ else:
+ macst.latchCvtStopTrue = False
+ macst.latchCvtStopFalse = True
+ elif msg.topic == "latch/status/arm/suck":
+ if str(msg.payload) == "true":
+ macst.latchSuckStopTrue = True
+ macst.latchSuckStopFalse = False
+ else:
+ macst.latchSuckStopTrue = False
+ macst.latchSuckStopFalse = True
+ elif msg.topic == "latch/status/bowl/cnt":
+ macst.strBowlCnt = str(msg.payload)
+ elif msg.topic == "latch/status/bowl/ready":
+ if str(msg.payload) == "true":
+ macst.latchBowlReadyTrue = True
+ macst.latchBowlReadyFalse = False
+ # logger.trace('Ready:True');
+ else:
+ macst.latchBowlReadyTrue = False
+ macst.latchBowlReadyFalse = True
+ # logger.trace('Ready:False'); }
+ elif msg.topic == "latch/status/gate/open":
+ if str(msg.payload) == "true":
+ macst.latchGateOpenTrue = True
+ macst.latchGateOpenFalse = False
+ # logger.trace('gateCmd:True');
+ else:
+ macst.latchGateOpenTrue = False
+ macst.latchGateOpenFalse = True
+ # logger.trace('gateCmd:False');}
+ elif msg.topic == "latch/status/fan/open":
+ if str(msg.payload) == "true":
+ macst.latchFanOpenTrue = True
+ macst.latchFanOpenFalse = False
+ # logger.trace('fanCmd:True');
+ else:
+ macst.latchFanOpenTrue = False
+ macst.latchFanOpenFalse = True
+ # logger.trace('fanCmd:False');}
+ elif msg.topic == "latch/status/vibration":
+ if str(msg.payload) == "true":
+ macst.latchVibrationTrue = True
+ macst.latchVibrationFalse = False
+ # logger.trace('vCmd:True');
+ else:
+ macst.latchVibrationTrue = False
+ macst.latchVibrationFalse = True
+ # logger.trace('vCmd:False');}
+ elif msg.topic == "latch/status/arm/pos":
+ macst.strArmPos = str(msg.payload)
+ # logger.trace(strArmPos);
+ elif msg.topic == "latch/status/cvt/pos":
+ macst.strCvtPos = str(msg.payload)
+ # logger.trace(strCvtPos);
+ elif msg.topic == "latch/status/arm/release":
+ if str(msg.payload) == "true":
+ macst.latchArmReleaseTrue = True
+ macst.latchArmReleaseFalse = False
+ else:
+ macst.latchArmReleaseTrue = False
+ macst.latchArmReleaseFalse = True
+
+
+def move_robot(target, pos, isPass="WAIT"):
+ global mqttc, macst
+ macst.robotMotionDone = False
+ mqttc.publish("robot/cmd/jog/" + target, pos)
+ if isPass != "PASS":
+ while macst.robotMotionDone == False:
+ logger.debug("robotMotionDone: " + str(macst.robotMotionDone))
+ time.sleep(0.1)
+
+
+def spit_cake(vol):
+ global mqttc, macst
+ macst.bucketStopTrue = False
+ mqttc.publish("bucket/cmd/jog/vol", vol)
+ while macst.bucketStopTrue == False:
+ logger.debug("bucketStopTrue: " + str(macst.bucketStopTrue))
+ time.sleep(0.1)
+
+
+def close_oven():
+ global mqttc, macst
+ macst.ovenOpenFalse = False
+ mqttc.publish("oven/cmd/open", "false")
+ while macst.ovenOpenFalse == False:
+ logger.debug("ovenOpenFalse: " + str(macst.ovenOpenFalse))
+ time.sleep(0.1)
+
+
+def move_robot_and_spit(pnt_name, pos, vol):
+ move_robot("y", pos)
+ logger.info("robot move to " + pnt_name)
+ spit_cake(vol)
+ logger.info("spit to " + pnt_name)
+
+
+def flip_oven(cmd):
+ global mqttc, macst
+ if cmd == True:
+ macst.ovenFlipTrue = False
+ mqttc.publish("oven/cmd/flip", "true")
+ while macst.ovenFlipTrue == False:
+ logger.debug("ovenFlipTrue: " + str(macst.ovenFlipTrue))
+ time.sleep(0.1)
+ else:
+ macst.ovenFlipFalse = False
+ mqttc.publish("oven/cmd/flip", "false")
+ while macst.ovenFlipFalse == False:
+ logger.debug("ovenFlipFalse: " + str(macst.ovenFlipFalse))
+ time.sleep(0.1)
+
+
+def robot_go_home():
+ global mqttc, macst
+ macst.robotMotionDone = False
+ mqttc.publish("robot/cmd/home/z", "true")
+ mqttc.publish("robot/cmd/home/y", "true")
+ mqttc.publish("robot/cmd/home/x", "true")
+ while macst.robotMotionDone == False:
+ logger.debug("robotMotionDone: " + str(macst.robotMotionDone))
+ time.sleep(0.1)
+
+
+def pick_cake_and_drop(pnt_name, pos_y):
+ global mqttc, macst
+ move_robot("x", "210", "PASS")
+ move_robot("y", pos_y, "PASS")
+ mqttc.publish("robot/cmd/jog/fork", "0") # gripper OPEN
+ move_robot("z", "-105")
+ logger.info("robot to upper " + pnt_name)
+ mqttc.publish("robot/cmd/jog/fork", "50") # gripper CLOSE
+ logger.info("robot grip at " + pnt_name)
+ move_robot("z", "-70")
+ logger.info("robot move up to " + pnt_name)
+ move_robot("x", "0", "PASS")
+ move_robot("y", "-130", "PASS")
+ move_robot("z", "-70")
+ mqttc.publish("robot/cmd/jog/fork", "0") # gripper OPEN
+ logger.info("robot drop cake")
+
+
+def unloading():
+ global mqttc, macst
+ macst.latchBowlReadyTrue = False
+ while macst.latchBowlReadyTrue == False:
+ logger.debug("latchBowlReadyTrue: " + str(macst.latchBowlReadyTrue))
+ time.sleep(0.1)
+
+ # open latch fan
+ macst.latchFanOpenTrue = False
+ mqttc.publish("latch/cmd/fan/open", "true")
+ logger.info("10")
+ while macst.latchFanOpenTrue == False:
+ logger.debug("latchFanOpenTrue: " + str(macst.latchFanOpenTrue))
+ time.sleep(0.1)
+
+ # open latch gate
+ macst.latchGateOpenTrue = False
+ mqttc.publish("latch/cmd/gate/open", "true")
+ logger.info("11")
+ while macst.latchGateOpenTrue == False:
+ logger.debug("latchGateOpenTrue: " + str(macst.latchGateOpenTrue))
+ time.sleep(0.1)
+ time.sleep(4)
+ logger.info("12")
+
+ # close latch gate
+ macst.latchGateOpenFalse = False
+ mqttc.publish("latch/cmd/gate/open", "false")
+ while macst.latchGateOpenFalse == False:
+ logger.debug("latchGateOpenFalse: " + str(macst.latchGateOpenFalse))
+ time.sleep(0.1)
+ time.sleep(1.5)
+ logger.info("13")
+
+ # close latch fan
+ macst.latchFanOpenFalse = False
+ mqttc.publish("latch/cmd/fan/open", "false")
+ while macst.latchFanOpenFalse == False:
+ logger.debug("latchFanOpenFalse: " + str(macst.latchFanOpenFalse))
+ time.sleep(0.1)
+ time.sleep(0.5)
+ logger.info("14")
+
+ logger.warning("strBowlCnt: " + macst.strBowlCnt)
+ logger.info("Stock Bowl Process finish!")
+
+
+def ctrl_oven_and_robot():
+ global mqttc, latchTakeBowl_Start
+ logger.warning('control oven and robot thread start')
+
+ latchTakeBowl_Start = True
+ logger.info("main script start!")
+
+ mqttc.publish("robot/cmd/jog/vel", "300")
+ mqttc.publish("bucket/cmd/jog/vel", "300")
+
+ mqttc.publish("oven/cmd/open", "true")
+ logger.info("oven first open")
+ time.sleep(1.5)
+
+ move_robot("x", "240", "PASS")
+ move_robot("z", "-110", "PASS")
+
+ move_robot_and_spit("P1", "-15", "30")
+ move_robot_and_spit("P2", "-61", "33")
+ move_robot_and_spit("P3", "-107", "33")
+ move_robot_and_spit("P4", "-153", "33")
+ move_robot_and_spit("P5", "-199", "33")
+ move_robot_and_spit("P6", "-245", "33")
+
+ spit_cake("-10")
+ logger.info("pump suck back")
+
+ move_robot("x", "150")
+ logger.info("robot move to avoid point")
+
+ move_robot("x", "0", "PASS")
+ move_robot("y", "0", "PASS")
+ move_robot("z", "0")
+ logger.info("robot move to P0")
+
+ close_oven()
+ logger.info("close oven")
+
+ flip_oven(True)
+ logger.info("oven flip true")
+
+ # time.sleep(75)
+ time.sleep(1) # bake 1min 15s
+
+ flip_oven(False)
+ logger.info("oven flip false")
+
+ # time.sleep(120)
+ time.sleep(1) # bake 2min
+
+ robot_go_home()
+ logger.info("robot go home")
+
+ mqttc.publish("oven/cmd/open", "true")
+ logger.info("oven open")
+ time.sleep(1.5)
+
+ pick_cake_and_drop("P1", "-20")
+ pick_cake_and_drop("P2", "-66")
+ pick_cake_and_drop("P3", "-113")
+ pick_cake_and_drop("P4", "-158")
+ pick_cake_and_drop("P5", "-204")
+ pick_cake_and_drop("P6", "-250")
+
+ move_robot("x", "0", "PASS")
+ move_robot("y", "0", "PASS")
+ move_robot("z", "0")
+ logger.info("robot move to P0")
+
+ close_oven()
+ logger.info("close oven")
+
+ unloading()
+ logger.info("drop cake to bowl")
+
+ robot_go_home()
+ logger.info("robot go home")
+
+ logger.info("Process finish!!!!!!!!!!!!!")
+ logger.warning('control oven and robot thread end')
+
+
+def move_cvt(pos, delay):
+ global mqttc, macst
+ macst.latchCvtStopTrue = False
+ mqttc.publish("latch/cmd/cvt/pos", pos)
+ time.sleep(delay)
+ while macst.latchCvtStopTrue == False:
+ logger.debug("latchCvtStopTrue: " + str(macst.latchCvtStopTrue))
+ time.sleep(0.1)
+
+
+def move_arm(pos, delay):
+ global mqttc, macst
+ macst.latchArmStopTrue = False
+ mqttc.publish("latch/cmd/arm/pos", pos)
+ time.sleep(delay)
+ while macst.latchArmStopTrue == False:
+ logger.debug("latchArmStopTrue: " + str(macst.latchArmStopTrue))
+ time.sleep(0.1)
+
+
+def arm_suck(cmd, delay):
+ global mqttc, macst
+ if cmd == True:
+ macst.latchSuckStopTrue = False
+ mqttc.publish("latch/cmd/arm/suck", "true")
+ time.sleep(delay)
+ while macst.latchSuckStopTrue == False:
+ logger.debug("latchSuckStopTrue: " + str(macst.latchSuckStopTrue))
+ time.sleep(0.1)
+ else:
+ macst.latchSuckStopFalse = False
+ mqttc.publish("latch/cmd/arm/suck", "false")
+ time.sleep(delay)
+ while macst.latchSuckStopFalse == False:
+ logger.debug("latchSuckStopFalse: " +
+ str(macst.latchSuckStopFalse))
+ time.sleep(0.1)
+
+
+def ctrl_latch():
+ global macst, latchTakeBowl_Start
+ waitTime = 0.1
+ global mqttc
+ logger.warning('control latch thread start')
+ logger.info('sub script start!')
+
+ # set arm speed
+ mqttc.publish("latch/cmd/arm/vel", "40")
+ time.sleep(waitTime)
+
+ # set cvt speed
+ mqttc.publish("latch/cmd/cvt/vel", "130")
+ time.sleep(waitTime)
+
+ latchTakeBowl_Start = True
+
+ while latchTakeBowl_Start == False:
+ logger.debug("latchTakeBowl_Start: " + str(latchTakeBowl_Start))
+ time.sleep(0.1)
+
+ retry_take_bowl = 0
+
+ while True:
+ # move cvt to bowl
+ logger.info('01')
+ move_cvt("-202", 2)
+
+ # move arm up to bowl
+ logger.info('02')
+ # offset the arm
+ offset = retry_take_bowl % 3
+ if offset == 0:
+ move_arm("110", 3)
+ elif offset == 1:
+ move_arm("112", 3)
+ elif offset == 2:
+ move_arm("115", 3)
+
+ # suck the bowl
+ logger.info('03')
+ arm_suck(True, 0.3)
+
+ # move arm down
+ logger.info('04')
+ move_arm("22", 2)
+
+ # release the bowl
+ logger.info('05')
+ arm_suck(False, 4)
+
+ # move arm to home
+ logger.info('06')
+ move_arm("0", 1.5)
+
+ # move cvt to catch the cake
+ logger.info('07')
+ move_cvt("0", 2)
+
+ #
+ logger.info('08')
+ time.sleep(0.5)
+ retry_take_bowl = retry_take_bowl + 1
+
+ # confirm the cake was catched
+ if macst.latchBowlReadyTrue == False and retry_take_bowl < 10:
+ continue
+ else:
+ break
+
+ # suck bowl multiple fail
+ if retry_take_bowl >= 10:
+ logger.fatal("take bowl error!")
+
+ latchTakeBowl_Start = False
+
+ logger.warning('control latch thread end')
+
+
+logger = logging.getLogger('recipe')
+logger.setLevel(logging.DEBUG)
+# create file handler which logs even debug messages
+log_filename = str(datetime.now().strftime('recipe_%Y%m%d%H%M%S'))
+fh = logging.FileHandler(
+ 'log/{0}.log'.format(log_filename))
+fh.setLevel(logging.INFO)
+# create console handler with a higher log level
+ch = logging.StreamHandler()
+ch.setLevel(logging.INFO)
+# create formatter and add it to the handlers
+formatter = logging.Formatter(
+ '%(asctime)s %(levelname)s(%(filename)s:%(lineno)d): %(message)s', datefmt='%Y%m%d%H%M%S')
+ch.setFormatter(formatter)
+fh.setFormatter(formatter)
+# add the handlers to logger
+logger.addHandler(ch)
+logger.addHandler(fh)
+
+logger.warning('recipe start')
+mqttc = mqtt.Client(client_id="recipe")
+# mqttc.on_publish = on_publish
+# mqttc.on_subscribe = on_subscribe
+# mqttc.on_log = on_log
+mqttc.on_message = on_message
+mqttc.on_connect = on_connect
+mqttc.connect("localhost", 1883, 60)
+mqttc.loop_start()
+
+thread1 = threading.Thread(target=ctrl_oven_and_robot)
+thread2 = threading.Thread(target=ctrl_latch)
+
+thread1.start()
+thread2.start()
+
+thread1.join()
+thread2.join()
+
+mqttc.disconnect()
+mqttc.loop_stop()
+logger.warning("recipe done")
diff --git a/recipe/py/test0413.py b/recipe/py/test0413.py
new file mode 100644
index 0000000..32eea73
--- /dev/null
+++ b/recipe/py/test0413.py
@@ -0,0 +1,539 @@
+import paho.mqtt.client as mqtt
+import signal
+import time
+import threading
+import logging
+from datetime import datetime
+
+
+class machineStatus:
+ robotMotionDone = True
+ ovenFlipTrue = False
+ ovenFlipFalse = False
+ ovenOpenTrue = False
+ ovenOpenFalse = False
+ bucketStopTrue = False
+ latchArmStopTrue = False
+ latchArmStopFalse = False
+ latchCvtStopTrue = False
+ latchCvtStopFalse = False
+ latchSuckStopTrue = False
+ latchSuckStopFalse = False
+ latchBowlReadyTrue = False
+ latchBowlReadyFalse = False
+ latchGateOpenTrue = False
+ latchGateOpenFalse = False
+ latchFanOpenTrue = False
+ latchFanOpenFalse = False
+ strBowlCnt = "0"
+ strArmPos = "0"
+ strCvtPos = "0"
+
+
+macst = machineStatus()
+looping = False
+mqttc = None
+latchTakeBowl_Start = False
+
+# def on_publish(mqttc, obj, mid):
+# logger.debug("mid: " + str(mid))
+# pass
+
+
+# def on_subscribe(mqttc, obj, mid, granted_qos):
+# logger.debug("Subscribed: " + str(mid) + " " + str(granted_qos))
+
+
+# def on_log(mqttc, obj, level, string):
+# logger.debug(string)
+
+def stop_all(*args):
+ global looping
+ looping = False
+
+
+def on_connect(mqttc, obj, flags, rc):
+ logger.warning('broker connected')
+ mqttc.subscribe('robot/status/stop')
+ mqttc.subscribe('oven/status/flip')
+ mqttc.subscribe('oven/status/open')
+ mqttc.subscribe('bucket/status/stop')
+ mqttc.subscribe('latch/status/arm/stop')
+ mqttc.subscribe('latch/status/cvt/stop')
+ mqttc.subscribe('latch/status/bowl/cnt')
+ mqttc.subscribe('latch/status/bowl/ready')
+ mqttc.subscribe('latch/status/arm/suck')
+ mqttc.subscribe('latch/status/arm/release')
+ mqttc.subscribe('latch/status/gate/open')
+ mqttc.subscribe('latch/status/fan/open')
+ mqttc.subscribe('latch/status/vibration')
+ mqttc.subscribe('latch/status/arm/pos')
+ mqttc.subscribe('latch/status/cvt/pos')
+
+
+def on_message(mqttc, obj, msg):
+ global macst
+ logger.debug(msg.topic + ": " + str(msg.payload))
+ if msg.topic == "robot/status/stop":
+ if str(msg.payload) == "true":
+ macst.robotMotionDone = True
+ else:
+ macst.robotMotionDone = False
+ elif msg.topic == "oven/status/flip":
+ if str(msg.payload) == "true":
+ macst.ovenFlipTrue = True
+ macst.ovenFlipFalse = False
+ else:
+ macst.ovenFlipTrue = False
+ macst.ovenFlipFalse = True
+ elif msg.topic == "oven/status/open":
+ if str(msg.payload) == "true":
+ macst.ovenOpenTrue = True
+ macst.ovenOpenFalse = False
+ else:
+ macst.ovenOpenTrue = False
+ macst.ovenOpenFalse = True
+ elif msg.topic == "bucket/status/stop":
+ if str(msg.payload) == "true":
+ macst.bucketStopTrue = True
+ macst.bucketStopFalse = False
+ else:
+ macst.bucketStopTrue = False
+ macst.bucketStopFalse = True
+ elif msg.topic == "latch/status/arm/stop":
+ if str(msg.payload) == "true":
+ macst.latchArmStopTrue = True
+ macst.latchArmStopFalse = False
+ else:
+ macst.latchArmStopTrue = False
+ macst.latchArmStopFalse = True
+ elif msg.topic == "latch/status/cvt/stop":
+ if str(msg.payload) == "true":
+ macst.latchCvtStopTrue = True
+ macst.latchCvtStopFalse = False
+ else:
+ macst.latchCvtStopTrue = False
+ macst.latchCvtStopFalse = True
+ elif msg.topic == "latch/status/arm/suck":
+ if str(msg.payload) == "true":
+ macst.latchSuckStopTrue = True
+ macst.latchSuckStopFalse = False
+ else:
+ macst.latchSuckStopTrue = False
+ macst.latchSuckStopFalse = True
+ elif msg.topic == "latch/status/bowl/cnt":
+ macst.strBowlCnt = str(msg.payload)
+ elif msg.topic == "latch/status/bowl/ready":
+ if str(msg.payload) == "true":
+ macst.latchBowlReadyTrue = True
+ macst.latchBowlReadyFalse = False
+ # logger.trace('Ready:True');
+ else:
+ macst.latchBowlReadyTrue = False
+ macst.latchBowlReadyFalse = True
+ # logger.trace('Ready:False'); }
+ elif msg.topic == "latch/status/gate/open":
+ if str(msg.payload) == "true":
+ macst.latchGateOpenTrue = True
+ macst.latchGateOpenFalse = False
+ # logger.trace('gateCmd:True');
+ else:
+ macst.latchGateOpenTrue = False
+ macst.latchGateOpenFalse = True
+ # logger.trace('gateCmd:False');}
+ elif msg.topic == "latch/status/fan/open":
+ if str(msg.payload) == "true":
+ macst.latchFanOpenTrue = True
+ macst.latchFanOpenFalse = False
+ # logger.trace('fanCmd:True');
+ else:
+ macst.latchFanOpenTrue = False
+ macst.latchFanOpenFalse = True
+ # logger.trace('fanCmd:False');}
+ elif msg.topic == "latch/status/vibration":
+ if str(msg.payload) == "true":
+ macst.latchVibrationTrue = True
+ macst.latchVibrationFalse = False
+ # logger.trace('vCmd:True');
+ else:
+ macst.latchVibrationTrue = False
+ macst.latchVibrationFalse = True
+ # logger.trace('vCmd:False');}
+ elif msg.topic == "latch/status/arm/pos":
+ macst.strArmPos = str(msg.payload)
+ # logger.trace(strArmPos);
+ elif msg.topic == "latch/status/cvt/pos":
+ macst.strCvtPos = str(msg.payload)
+ # logger.trace(strCvtPos);
+ elif msg.topic == "latch/status/arm/release":
+ if str(msg.payload) == "true":
+ macst.latchArmReleaseTrue = True
+ macst.latchArmReleaseFalse = False
+ else:
+ macst.latchArmReleaseTrue = False
+ macst.latchArmReleaseFalse = True
+
+
+def move_robot(target, pos, isPass="WAIT"):
+ global mqttc, macst
+ macst.robotMotionDone = False
+ mqttc.publish("robot/cmd/jog/" + target, pos)
+ if isPass != "PASS":
+ while macst.robotMotionDone == False:
+ logger.debug("robotMotionDone: " + str(macst.robotMotionDone))
+ time.sleep(0.1)
+
+
+def spit_cake(vol):
+ global mqttc, macst
+ macst.bucketStopTrue = False
+ mqttc.publish("bucket/cmd/jog/vol", vol)
+ while macst.bucketStopTrue == False:
+ logger.debug("bucketStopTrue: " + str(macst.bucketStopTrue))
+ time.sleep(0.1)
+
+
+def close_oven():
+ global mqttc, macst
+ macst.ovenOpenFalse = False
+ mqttc.publish("oven/cmd/open", "false")
+ while macst.ovenOpenFalse == False:
+ logger.debug("ovenOpenFalse: " + str(macst.ovenOpenFalse))
+ time.sleep(0.1)
+
+
+def move_robot_and_spit(pnt_name, pos, vol):
+ move_robot("y", pos)
+ logger.info("robot move to " + pnt_name)
+ spit_cake(vol)
+ logger.info("spit to " + pnt_name)
+
+
+def flip_oven(cmd):
+ global mqttc, macst
+ if cmd == True:
+ macst.ovenFlipTrue = False
+ mqttc.publish("oven/cmd/flip", "true")
+ while macst.ovenFlipTrue == False:
+ logger.debug("ovenFlipTrue: " + str(macst.ovenFlipTrue))
+ time.sleep(0.1)
+ else:
+ macst.ovenFlipFalse = False
+ mqttc.publish("oven/cmd/flip", "false")
+ while macst.ovenFlipFalse == False:
+ logger.debug("ovenFlipFalse: " + str(macst.ovenFlipFalse))
+ time.sleep(0.1)
+
+
+def robot_go_home():
+ global mqttc, macst
+ macst.robotMotionDone = False
+ mqttc.publish("robot/cmd/home/z", "true")
+ mqttc.publish("robot/cmd/home/y", "true")
+ mqttc.publish("robot/cmd/home/x", "true")
+ while macst.robotMotionDone == False:
+ logger.debug("robotMotionDone: " + str(macst.robotMotionDone))
+ time.sleep(0.1)
+
+
+def pick_cake_and_drop(pnt_name, pos_y):
+ global mqttc, macst
+ move_robot("x", "210", "PASS")
+ move_robot("y", pos_y, "PASS")
+ mqttc.publish("robot/cmd/jog/fork", "0") # gripper OPEN
+ move_robot("z", "-105")
+ logger.info("robot to upper " + pnt_name)
+ mqttc.publish("robot/cmd/jog/fork", "50") # gripper CLOSE
+ logger.info("robot grip at " + pnt_name)
+ move_robot("z", "-70")
+ logger.info("robot move up to " + pnt_name)
+ move_robot("x", "0", "PASS")
+ move_robot("y", "-130", "PASS")
+ move_robot("z", "-70")
+ mqttc.publish("robot/cmd/jog/fork", "0") # gripper OPEN
+ logger.info("robot drop cake")
+
+
+def unloading():
+ global mqttc, macst
+ macst.latchBowlReadyTrue = False
+ while macst.latchBowlReadyTrue == False:
+ logger.debug("latchBowlReadyTrue: " + str(macst.latchBowlReadyTrue))
+ time.sleep(0.1)
+
+ # open latch fan
+ macst.latchFanOpenTrue = False
+ mqttc.publish("latch/cmd/fan/open", "true")
+ logger.info("10")
+ while macst.latchFanOpenTrue == False:
+ logger.debug("latchFanOpenTrue: " + str(macst.latchFanOpenTrue))
+ time.sleep(0.1)
+
+ # open latch gate
+ macst.latchGateOpenTrue = False
+ mqttc.publish("latch/cmd/gate/open", "true")
+ logger.info("11")
+ while macst.latchGateOpenTrue == False:
+ logger.debug("latchGateOpenTrue: " + str(macst.latchGateOpenTrue))
+ time.sleep(0.1)
+ time.sleep(4)
+ logger.info("12")
+
+ # close latch gate
+ macst.latchGateOpenFalse = False
+ mqttc.publish("latch/cmd/gate/open", "false")
+ while macst.latchGateOpenFalse == False:
+ logger.debug("latchGateOpenFalse: " + str(macst.latchGateOpenFalse))
+ time.sleep(0.1)
+ time.sleep(1.5)
+ logger.info("13")
+
+ # close latch fan
+ macst.latchFanOpenFalse = False
+ mqttc.publish("latch/cmd/fan/open", "false")
+ while macst.latchFanOpenFalse == False:
+ logger.debug("latchFanOpenFalse: " + str(macst.latchFanOpenFalse))
+ time.sleep(0.1)
+ time.sleep(0.5)
+ logger.info("14")
+
+ logger.warning("strBowlCnt: " + macst.strBowlCnt)
+ logger.info("Stock Bowl Process finish!")
+
+
+def ctrl_oven_and_robot():
+ global mqttc, latchTakeBowl_Start
+ logger.warning('control oven and robot thread start')
+
+ latchTakeBowl_Start = True
+ logger.info("main script start!")
+
+ mqttc.publish("robot/cmd/jog/vel", "300")
+ mqttc.publish("bucket/cmd/jog/vel", "300")
+
+ mqttc.publish("oven/cmd/open", "true")
+ logger.info("oven first open")
+ time.sleep(1.5)
+
+ move_robot("x", "240", "PASS")
+ move_robot("z", "-110", "PASS")
+
+ move_robot_and_spit("P1", "-15", "30")
+ move_robot_and_spit("P2", "-61", "33")
+ move_robot_and_spit("P3", "-107", "33")
+ move_robot_and_spit("P4", "-153", "33")
+ move_robot_and_spit("P5", "-199", "33")
+ move_robot_and_spit("P6", "-245", "33")
+
+ spit_cake("-10")
+ logger.info("pump suck back")
+
+ move_robot("x", "150")
+ logger.info("robot move to avoid point")
+
+ move_robot("x", "0", "PASS")
+ move_robot("y", "0", "PASS")
+ move_robot("z", "0")
+ logger.info("robot move to P0")
+
+ close_oven()
+ logger.info("close oven")
+
+ flip_oven(True)
+ logger.info("oven flip true")
+
+ # time.sleep(75)
+ time.sleep(1) # bake 1min 15s
+
+ flip_oven(False)
+ logger.info("oven flip false")
+
+ # time.sleep(120)
+ time.sleep(1) # bake 2min
+
+ robot_go_home()
+ logger.info("robot go home")
+
+ mqttc.publish("oven/cmd/open", "true")
+ logger.info("oven open")
+ time.sleep(1.5)
+
+ pick_cake_and_drop("P1", "-20")
+ pick_cake_and_drop("P2", "-66")
+ pick_cake_and_drop("P3", "-113")
+ pick_cake_and_drop("P4", "-158")
+ pick_cake_and_drop("P5", "-204")
+ pick_cake_and_drop("P6", "-250")
+
+ move_robot("x", "0", "PASS")
+ move_robot("y", "0", "PASS")
+ move_robot("z", "0")
+ logger.info("robot move to P0")
+
+ close_oven()
+ logger.info("close oven")
+
+ unloading()
+ logger.info("drop cake to bowl")
+
+ robot_go_home()
+ logger.info("robot go home")
+
+ logger.info("Process finish!!!!!!!!!!!!!")
+ logger.warning('control oven and robot thread end')
+
+
+def move_cvt(pos, delay):
+ global mqttc, macst
+ macst.latchCvtStopTrue = False
+ mqttc.publish("latch/cmd/cvt/pos", pos)
+ time.sleep(delay)
+ while macst.latchCvtStopTrue == False:
+ logger.debug("latchCvtStopTrue: " + str(macst.latchCvtStopTrue))
+ time.sleep(0.1)
+
+
+def move_arm(pos, delay):
+ global mqttc, macst
+ macst.latchArmStopTrue = False
+ mqttc.publish("latch/cmd/arm/pos", pos)
+ time.sleep(delay)
+ while macst.latchArmStopTrue == False:
+ logger.debug("latchArmStopTrue: " + str(macst.latchArmStopTrue))
+ time.sleep(0.1)
+
+
+def arm_suck(cmd, delay):
+ global mqttc, macst
+ if cmd == True:
+ macst.latchSuckStopTrue = False
+ mqttc.publish("latch/cmd/arm/suck", "true")
+ time.sleep(delay)
+ while macst.latchSuckStopTrue == False:
+ logger.debug("latchSuckStopTrue: " + str(macst.latchSuckStopTrue))
+ time.sleep(0.1)
+ else:
+ macst.latchSuckStopFalse = False
+ mqttc.publish("latch/cmd/arm/suck", "false")
+ time.sleep(delay)
+ while macst.latchSuckStopFalse == False:
+ logger.debug("latchSuckStopFalse: " +
+ str(macst.latchSuckStopFalse))
+ time.sleep(0.1)
+
+
+def ctrl_latch():
+ global macst, latchTakeBowl_Start
+ waitTime = 0.1
+ global mqttc
+ logger.warning('control latch thread start')
+ logger.info('sub script start!')
+
+ # set arm speed
+ mqttc.publish("latch/cmd/arm/vel", "40")
+ time.sleep(waitTime)
+
+ # set cvt speed
+ mqttc.publish("latch/cmd/cvt/vel", "130")
+ time.sleep(waitTime)
+
+ latchTakeBowl_Start = True
+
+ while latchTakeBowl_Start == False:
+ logger.debug("latchTakeBowl_Start: " + str(latchTakeBowl_Start))
+ time.sleep(0.1)
+
+ retry_take_bowl = 0
+
+ while True:
+ # move cvt to bowl
+ logger.info('01')
+ move_cvt("-202", 2)
+
+ # move arm up to bowl
+ logger.info('02')
+ # offset the arm
+ offset = retry_take_bowl % 3
+ if offset == 0:
+ move_arm("110", 3)
+ elif offset == 1:
+ move_arm("112", 3)
+ elif offset == 2:
+ move_arm("115", 3)
+
+ # suck the bowl
+ logger.info('03')
+ arm_suck(True, 0.3)
+
+ # move arm down
+ logger.info('04')
+ move_arm("22", 2)
+
+ # release the bowl
+ logger.info('05')
+ arm_suck(False, 4)
+
+ # move arm to home
+ logger.info('06')
+ move_arm("0", 1.5)
+
+ # move cvt to catch the cake
+ logger.info('07')
+ move_cvt("0", 2)
+
+ #
+ logger.info('08')
+ time.sleep(0.5)
+ retry_take_bowl = retry_take_bowl + 1
+
+ # confirm the cake was catched
+ if macst.latchBowlReadyTrue == False and retry_take_bowl < 10:
+ continue
+ else:
+ break
+
+ # suck bowl multiple fail
+ if retry_take_bowl >= 10:
+ logger.fatal("take bowl error!")
+
+ latchTakeBowl_Start = False
+
+ logger.warning('control latch thread end')
+
+
+# signal.signal(signal.SIGTERM, stop_all)
+# signal.signal(signal.SIGQUIT, stop_all)
+# signal.signal(signal.SIGINT, stop_all) # Ctrl-C
+log_filename = str(datetime.now().strftime('recipe_%Y%m%d%H%M%S'))
+LOGGING_FORMAT = '%(asctime)s %(levelname)s(%(filename)s:%(lineno)d): %(message)s'
+DATE_FORMAT = '%Y%m%d%H%M%S'
+logging.basicConfig(level=logging.INFO,
+ format=LOGGING_FORMAT,
+ datefmt=DATE_FORMAT,
+ handlers=[
+ logging.FileHandler(
+ 'log/{0}.log'.format(log_filename)),
+ logging.StreamHandler()
+ ])
+logger.warning('recipe start')
+mqttc = mqtt.Client(client_id="recipe")
+# mqttc.on_publish = on_publish
+# mqttc.on_subscribe = on_subscribe
+# mqttc.on_log = on_log
+mqttc.on_message = on_message
+mqttc.on_connect = on_connect
+mqttc.connect("localhost", 1883, 60)
+mqttc.loop_start()
+
+thread1 = threading.Thread(target=ctrl_oven_and_robot)
+thread2 = threading.Thread(target=ctrl_latch)
+
+thread1.start()
+thread2.start()
+
+thread1.join()
+thread2.join()
+
+mqttc.disconnect()
+mqttc.loop_stop()
+logger.warning("recipe done")
diff --git a/recipe/py/test2.py b/recipe/py/test2.py
new file mode 100644
index 0000000..4a296ec
--- /dev/null
+++ b/recipe/py/test2.py
@@ -0,0 +1,26 @@
+import logging
+from datetime import datetime
+
+
+logger = logging.getLogger('server_logger')
+logger.setLevel(logging.DEBUG)
+# create file handler which logs even debug messages
+log_filename = str(datetime.now().strftime('recipe_%Y%m%d%H%M%S'))
+fh = logging.FileHandler(
+ 'log/{0}.log'.format(log_filename))
+fh.setLevel(logging.INFO)
+# create console handler with a higher log level
+ch = logging.StreamHandler()
+ch.setLevel(logging.INFO)
+# create formatter and add it to the handlers
+formatter = logging.Formatter(
+ '%(asctime)s %(levelname)s(%(filename)s:%(lineno)d): %(message)s', datefmt='%Y%m%d%H%M%S')
+ch.setFormatter(formatter)
+fh.setFormatter(formatter)
+# add the handlers to logger
+logger.addHandler(ch)
+logger.addHandler(fh)
+
+logger.warning('recipe start 1')
+logger.warning('recipe start 2')
+logger.warning('recipe start 3')
diff --git a/recipes/test.js b/recipes/test.js
deleted file mode 100644
index f5721d7..0000000
--- a/recipes/test.js
+++ /dev/null
@@ -1 +0,0 @@
-console.log('I am test recipe');
\ No newline at end of file
diff --git a/serialmqtt/index.js b/serialmqtt/index.js
deleted file mode 100644
index bb21a0e..0000000
--- a/serialmqtt/index.js
+++ /dev/null
@@ -1,54 +0,0 @@
-const serialPort = require('serialport')
-const mega2560Serial = new serialPort('/dev/ttyACM0', {
- baudRate: 115200
-})
-const mqtt = require('mqtt');
-const mqttOpt = {
- port: 1883,
- clientId: "serialmqtt",
-};
-const mqttClient = mqtt.connect("mqtt://localhost", mqttOpt);
-
-// Switches the port into "flowing mode"
-mega2560Serial.on('readable', function () {
- console.log('mega2560:', mega2560Serial.read().toString('ascii'))
-});
-
-mqttClient.on("connect", function () {
- console.log("mqttClient: connect to broker");
- mqttClient.subscribe("robot/cmd/#");
-});
-
-const serialEnd = "\r\n";
-
-function sendSerialCmd (cmd) {
- console.log("sendSerialCmd: " + cmd);
- mega2560Serial.write(cmd + serialEnd);
-};
-
-function move (dir, len) {
- sendSerialCmd("G01 " + dir + len);
-};
-
-mqttClient.on("message", function (topic, msg) {
- console.log("mqttClient: topic " + topic + ", msg " + msg);
- switch (topic) {
- default:
- break;
- case "robot/cmd/jog/vel":
- move("F", "1000");
- break;
- case "robot/cmd/jog/x":
- move("X", msg);
- break;
- case "robot/cmd/jog/y":
- move("Y", msg);
- break;
- case "robot/cmd/jog/z":
- move("Z", msg);
- break;
- case "robot/cmd/stop":
- sendSerialCmd('blink');
- break;
- }
-});
diff --git a/serialmqtt/package.json b/serialmqtt/package.json
deleted file mode 100644
index ab757e4..0000000
--- a/serialmqtt/package.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "serialmqtt",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "start": "node ./index.js"
- },
- "author": "",
- "license": "MIT",
- "dependencies": {
- "mqtt": "^3.0.0",
- "serialport": "^7.1.5"
- }
-}
diff --git a/server/index.js b/server/index.js
new file mode 100644
index 0000000..8901ef7
--- /dev/null
+++ b/server/index.js
@@ -0,0 +1,43 @@
+const express = require("express");
+const app = express();
+const http = require("http");
+const https = require("https");
+const fs = require("fs");
+const bodyParser = require("body-parser");
+const cors = require("cors");
+const morgan = require("morgan");
+const axios = require("axios");
+const config = require("../config");
+const { SlackOAuthClient } = require("messaging-api-slack");
+
+const slackClient = SlackOAuthClient.connect(
+ "xoxb-1082926328692-1089407482497-XJENYGhYIJQrZRndVDGrk1aZ"
+);
+
+const https_options = {
+ key: fs.readFileSync("./ssl_files/server_private_key.pem"),
+ ca: [fs.readFileSync("./ssl_files/cert.pem")],
+ cert: fs.readFileSync("./ssl_files/server_cert.pem"),
+};
+
+app.use(cors());
+app.use(bodyParser.urlencoded({ extended: false }));
+app.use(bodyParser.text());
+app.use(morgan("dev"));
+
+app.get("/version", (req, res) => {
+ res.send(config.serverVersion);
+});
+
+app.post("/module/offline", (req, res) => {
+ slackClient.postMessage("#statusreport", req.body);
+ res.sendStatus(200);
+});
+
+http.createServer(app).listen(config.serverPort, () => {
+ console.log("cake vending server listening on port " + config.serverPort);
+});
+
+// https.createServer(https_options, app).listen(config.serverPort, () => {
+// console.log("cake vending server listening on port " + config.serverPort);
+// });
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 0000000..022f222
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "cake_vending_server",
+ "version": "1.0.0",
+ "description": "the server of all cake vending machines",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "start": "node index.js"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "axios": "^0.19.2",
+ "body-parser": "^1.19.0",
+ "cors": "^2.8.5",
+ "express": "^4.17.1",
+ "messaging-api-line": "^0.8.5",
+ "messaging-api-slack": "^0.8.2",
+ "morgan": "^1.9.1"
+ }
+}
diff --git a/server/ssl_files/cert.pem b/server/ssl_files/cert.pem
new file mode 100644
index 0000000..a1bd531
--- /dev/null
+++ b/server/ssl_files/cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDLzCCAhcCFBu0JJFW6jOM3w1W2ueE4fcNJWO2MA0GCSqGSIb3DQEBCwUAMFQx
+CzAJBgNVBAYTAlRXMQ8wDQYDVQQIDAZUQUlXQU4xETAPBgNVBAcMCFRBSUNIVU5H
+MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjAwNDIwMTY1
+NTI2WhcNNDcwOTA1MTY1NTI2WjBUMQswCQYDVQQGEwJUVzEPMA0GA1UECAwGVEFJ
+V0FOMREwDwYDVQQHDAhUQUlDSFVORzEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Xig7pVQ
+zU1irbcAfhHUwBE/SEOvhLgEof5xTiOSQWbXmh7BztCiWLavyp4eM+5L6B3Xa5Cn
+O9Kd6Fdr5zWF7liK171K0+8IzI7u/Vpg3o3t8B5E42JibJcYxzZ2t3dFL5+rUuTQ
+ROkTE0py76fzsMLolRsh2/nns4goslalZC1S0a/mf0VnHjQQOWUUyV205FIz5Lpw
+34S/DZfDA1RYJdvo8qJoNB7i+05T6S41FjOD+5RdOXR3BpDDGiwjxDLoV9+CXRUp
+jHuJKIyXzWHG+GqjKl/kW9H8bjupCPGGpwmCl4NLKOkXe2EJrBs+0W+3031jvAmy
+S7FCvRtUk24IzwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA6UxLYeJGAAG23u4F5
+WxMueNJk/o5uMHw3R9zgdbLSTkQtoptUWm16s1f31vG3D2P0CtWuibSq22aRpW22
+bYPzs2lRovywvAVMhZWVoSslH+cn2DJIfJuo7cPiklf53F3qSMt+GxZ4q2qOaV4T
+U3qWC8Jg03NOqoSJfx9Y9E6GWSNNl5GF03V4fgftrzDYGZuVBmoQLrU50v1HQvZX
+Zd1JkR5M8/A/QcNPQmz/Ze6aQ232VcZDMKCUpENhBItBcJDRsYAhH5yV75KsOQEC
+smhHgkfWY1Umwo+DzGER2QEb6p053A2cMs0yhY2BAEOXWCDQOZeRbrM99uCu4C6G
+PBEr
+-----END CERTIFICATE-----
diff --git a/server/ssl_files/cert.srl b/server/ssl_files/cert.srl
new file mode 100644
index 0000000..2ca3d85
--- /dev/null
+++ b/server/ssl_files/cert.srl
@@ -0,0 +1 @@
+7C5C2722C11C126C60B739E1106075BB3C99496C
diff --git a/server/ssl_files/csr.pem b/server/ssl_files/csr.pem
new file mode 100644
index 0000000..d3f8c55
--- /dev/null
+++ b/server/ssl_files/csr.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICmTCCAYECAQAwVDELMAkGA1UEBhMCVFcxDzANBgNVBAgMBlRBSVdBTjERMA8G
+A1UEBwwIVEFJQ0hVTkcxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
+ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN14oO6VUM1NYq23AH4R
+1MARP0hDr4S4BKH+cU4jkkFm15oewc7Qoli2r8qeHjPuS+gd12uQpzvSnehXa+c1
+he5Yite9StPvCMyO7v1aYN6N7fAeRONiYmyXGMc2drd3RS+fq1Lk0ETpExNKcu+n
+87DC6JUbIdv557OIKLJWpWQtUtGv5n9FZx40EDllFMldtORSM+S6cN+Evw2XwwNU
+WCXb6PKiaDQe4vtOU+kuNRYzg/uUXTl0dwaQwxosI8Qy6Fffgl0VKYx7iSiMl81h
+xvhqoypf5FvR/G47qQjxhqcJgpeDSyjpF3thCawbPtFvt9N9Y7wJskuxQr0bVJNu
+CM8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQDA9J2svIyONtRQyAgyKBDkinQG
+4UAw7s7LtXqTrzAtWb22iQPHwCKq9utY62MfGB7Sz45gY9PMwKNcF5ko5eI9w+Gr
+Wh7NSMSp4EMMAeDlpzfM4EgNfGmVwPriVxacAVwSnMyjHjmfFbwijqsBqOYF1kDT
+BRevIbgELJtzGOGVOJVQh+wiQs80XDWecZoN/+dK3MA6RtTMYftQDl3UxL99wJDe
+I/XK4qzsp8FKzPXFfdxcn+bkVIKT4BL6zk5JRexa8KmXhbQeq9SEj1BQ5X9q3onr
+NlujCDjY4KFV/JaIgCXPwJyFlbBY5qfloQeW4SG67iS03DUJ3bXHTv7GHC7l
+-----END CERTIFICATE REQUEST-----
diff --git a/server/ssl_files/private_key.pem b/server/ssl_files/private_key.pem
new file mode 100644
index 0000000..3a5e03b
--- /dev/null
+++ b/server/ssl_files/private_key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA3Xig7pVQzU1irbcAfhHUwBE/SEOvhLgEof5xTiOSQWbXmh7B
+ztCiWLavyp4eM+5L6B3Xa5CnO9Kd6Fdr5zWF7liK171K0+8IzI7u/Vpg3o3t8B5E
+42JibJcYxzZ2t3dFL5+rUuTQROkTE0py76fzsMLolRsh2/nns4goslalZC1S0a/m
+f0VnHjQQOWUUyV205FIz5Lpw34S/DZfDA1RYJdvo8qJoNB7i+05T6S41FjOD+5Rd
+OXR3BpDDGiwjxDLoV9+CXRUpjHuJKIyXzWHG+GqjKl/kW9H8bjupCPGGpwmCl4NL
+KOkXe2EJrBs+0W+3031jvAmyS7FCvRtUk24IzwIDAQABAoIBAAMmSAOck/2XcCPQ
+Sm2Ai2n/1MqOS9yzUT2MhMf7sYTElaRXc6IhTW29i1pyTTOn2+R9KCcbc4ViRWSc
+eahcFn+BOtg+lOXWrGVcUwG/W0lO82dKxugE6ilpLK0IlT+erpkyyBjxsBSKy/6m
+PGQ0Gz8URoJ4VE7wit7+vLVsjgWSqKdo3M0BH067WEN12r1kY5YlyaapSHlO8qnT
+tZtxnAdvM49CfvDtEj4eM+uB8kluIgWAWxmOB4Xf97hlPNbdaNDHhR+qXf/xDEug
+lTkqv9qutJF2xpsm1MR0aeQtexs7qES9GXrO/FRh6uKghmRSY4dYVOrwdK4MN1vJ
+sy8LquECgYEA+OYqmRZuVFkpknV8a+eluEzpmJuwLbqFGMIrcOAHMuuZ0lrB33P1
+GQetMjw5HUFnw3An64SzKEjhpGwLkK4d2nhdJF+Gmq9o71i1xzmsYkAAOFvg1tCU
+AoFa1hXxQp0CYBEM5ON5m09aJWPy9AZXdSu8MQXd9G/5saEw+b12180CgYEA48ok
+jtHJzZdD5nidV8iwBuG+XIkO5QrJ0ge/+nk3UOOr10pnEj+cSIa8CiIByOUpSxU1
+V+ku4f6l5FlDZOmEHKdh+1R+t/r/24yTj0W1HOknmgE3ngtljVlTi17Y6KZidwRw
+S+1pIScDy/XqfAC3nV9HKziKVeRCt5AWlfYkzwsCgYEAo3Ghr33HXaRfZEm6NrGb
+ZXc8PnaeLqk5FZUMKcczcwC7tiLbBP2Eibc8yKw7ZTa6CODxlftCGsYhRnOc9Jki
+CYDYyTXhklp1shay5+y7gpk8i8Xp06aMS0jeeY9XKsMn+CW6LeQiyxZEwCDuPcic
+Tdk2b4rGwel2MmsDWjxMelECgYBiBryixX8tvVnYFbHIdDHkVENieQzy3iip/PHN
+7VozsjZiKL+gZ8VupKTJS4cvGAckK5VQJqYpVTe4w/0vsRpMZm/RA7SgoiB3L9DU
+iC//qAqFyN5RYiAqqvU79e4seGXJSBy3YAys2qhUnphxErHxxG3RGLzXZ6qaaiR+
+FnYSrwKBgQDes1ajLPIcahljnxU9mzJEDajowXbQhKjb7w2b42eH5a+54uJBLNZ5
+MRgqmlkd9mavK6ap2siPNtHA/IVm+uf/8R2bU6I28uHHm3jBTa1K8NGwkvsWbopO
+T6KXAtXpQr3PKzfe5fAWVRCU8qgCgoUW/nf7BV5xfYHJzwmN1pgKpQ==
+-----END RSA PRIVATE KEY-----
diff --git a/server/ssl_files/server_cert.pem b/server/ssl_files/server_cert.pem
new file mode 100644
index 0000000..ec37e35
--- /dev/null
+++ b/server/ssl_files/server_cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUDCCAjigAwIBAgIUfFwnIsEcEmxgtznhEGB1uzyZSWwwDQYJKoZIhvcNAQEL
+BQAwVDELMAkGA1UEBhMCVFcxDzANBgNVBAgMBlRBSVdBTjERMA8GA1UEBwwIVEFJ
+Q0hVTkcxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA0
+MjAxNjU4MjVaFw0yMDA1MjAxNjU4MjVaMFQxCzAJBgNVBAYTAlRXMQ8wDQYDVQQI
+DAZUQUlXQU4xETAPBgNVBAcMCFRBSUNIVU5HMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCi
+BB9b+iLb+e6DPx7YmkvQ7+cHI3VCdvh6ZSFl8OMP5QX/dO5Jh/UZmPrHjGDssHaL
+AnyK2yCbviCFtJJtUNfqEl8WA65VhPJ2qsDF6wrS1jxayNmgIQfWdp6YTVp4bHir
+Psrzgfw58ZJ+VPDUZOdNbQcFZiS/XEApVxZP8MShfqYxQUwmOOeU3bBwc1BL5QE4
+ykzS4+U+OKO5dngLQgMcix/UcXwxzl/8dyPsYO+BOtPPc04BCiRO4CCKqyQ1KDU+
+D+KXnnFjO4KygNz2da8duQx8C0dm86GMM9sZKrAaFq+i505B9OgyTu+sZRBD1nfO
+6Ejmtw9G+7mxczA3PEHZAgMBAAGjGjAYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXg
+MA0GCSqGSIb3DQEBCwUAA4IBAQAJTu1s8n93fyz1/f7e6f1KehaYUDjpETdzZRF4
+45ysvtIFftvQrMGQnUFvTIDnBz4jcNdBQZ67+/G9sGP+KrDXRLJPhJD+hFzCOxGi
+CXALT/fiLIQsB3/gCR17y5dLtQYhB1c+khcs3Rl9qcq0JsGWifoZ61X2ySSIkbPp
+XH1utdHnqWE73Q3/YATX5FkWRdONXBEH5nkN4SAKpvhRIGqukn2SFlB0NomkR92I
+8/zMoWswhZoV+vtG/wyXenBJFTd+pNJHm8E3f0LBjNk+1VurX2vEFmTqbTgstNcq
+yTf5apsOeO1UK1nlhvbsrjfuKkQAOfdPWAfAhpeoypJ5Q2PD
+-----END CERTIFICATE-----
diff --git a/server/ssl_files/server_csr.pem b/server/ssl_files/server_csr.pem
new file mode 100644
index 0000000..3883350
--- /dev/null
+++ b/server/ssl_files/server_csr.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICmTCCAYECAQAwVDELMAkGA1UEBhMCVFcxDzANBgNVBAgMBlRBSVdBTjERMA8G
+A1UEBwwIVEFJQ0hVTkcxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0
+ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKIEH1v6Itv57oM/Htia
+S9Dv5wcjdUJ2+HplIWXw4w/lBf907kmH9RmY+seMYOywdosCfIrbIJu+IIW0km1Q
+1+oSXxYDrlWE8naqwMXrCtLWPFrI2aAhB9Z2nphNWnhseKs+yvOB/Dnxkn5U8NRk
+501tBwVmJL9cQClXFk/wxKF+pjFBTCY455TdsHBzUEvlATjKTNLj5T44o7l2eAtC
+AxyLH9RxfDHOX/x3I+xg74E6089zTgEKJE7gIIqrJDUoNT4P4peecWM7grKA3PZ1
+rx25DHwLR2bzoYwz2xkqsBoWr6LnTkH06DJO76xlEEPWd87oSOa3D0b7ubFzMDc8
+QdkCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQAizjMoB1cGuooh5D9TRMmOKtJI
+n5RQQVIdu2oS2W3wb7B+xuwea63T4DvoKdnQxJVJ4VCg+RVduKXDQ+T2Q71K0tTm
+2g96+3uBLbLyfWb4ARoXmhDiRxCUvRhI/DM3MMVKyCqu+su5dRjw9AMRGt5AlTyo
+1yEWmo2389SzZ1JKC+W4h1tBkpZr/bqoBjmAYOJODb23aitFEVac9CC+Rmg6AzSP
+xRDAayEVwJwlPRta7XZzVQWNZXfe2ipjtIa4flGwnDhrmjZd/SkAubWdxRak0Eay
+tMHXjKYrOndePpsaj6eZcadsZXsF32UNg8H/EgEgvJe/akejX8mNgF3OAzzL
+-----END CERTIFICATE REQUEST-----
diff --git a/server/ssl_files/server_private_key.pem b/server/ssl_files/server_private_key.pem
new file mode 100644
index 0000000..ba48912
--- /dev/null
+++ b/server/ssl_files/server_private_key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAogQfW/oi2/nugz8e2JpL0O/nByN1Qnb4emUhZfDjD+UF/3Tu
+SYf1GZj6x4xg7LB2iwJ8itsgm74ghbSSbVDX6hJfFgOuVYTydqrAxesK0tY8WsjZ
+oCEH1naemE1aeGx4qz7K84H8OfGSflTw1GTnTW0HBWYkv1xAKVcWT/DEoX6mMUFM
+JjjnlN2wcHNQS+UBOMpM0uPlPjijuXZ4C0IDHIsf1HF8Mc5f/Hcj7GDvgTrTz3NO
+AQokTuAgiqskNSg1Pg/il55xYzuCsoDc9nWvHbkMfAtHZvOhjDPbGSqwGhavoudO
+QfToMk7vrGUQQ9Z3zuhI5rcPRvu5sXMwNzxB2QIDAQABAoIBAFy2/zsjac94t4Vk
+GcLaiYiHwS3UnMXsT0W7meE8eLQf287Um4h4xUpgwSJwswa/9RaX1a2guIhnxTS+
+oQzttqG84a03bgyCiD5gePDKEOeWsfNB/UglntacCyYdHijL6kIVLQ8s06pVFAA3
+m5nwJG2qdtogGedoY09FBv+4SM4hQtILy72+ZEjhwN3MmG9hWI2p0BAOlyyJO+Xq
+GErUlWp/l7Qrn8c2HkPCTi3t4jFyVTDNe+3ADUi1WPFWcNG1LG+3T8A/hBldg2xX
+7o7tW00/rHmBvFYXoRBjuTkhQ64XMVbVmatWw68cJ2nIDl/be7lMjWFXjI4gslj7
+D5Cw2gECgYEA0H2DPLDJXol+fRbl/RTzRbloClMLDevsj69OCTnYAVUqZV4USW8P
+V5mAvzSX704Rvb/wkIo7WBWAKcz6CYrPngckBjUmTLUvoJuY7hZItUwn50IRPFje
+BxHjXKY7NsuH2XRju7aZLq7K/7Cbhj9txQOXYBN13gJQaeFD+aoIorsCgYEAxu9+
+E1NKm1fH+v93jHiEBsDljT6Lr5m4lJdw9sHRUpqsuhvpS1CThx4nMwYCjmcBuTTY
+DzCAMmO7eYjx9pGfX+sZvB1XWV6+zJ21grS8aiDkMRF4XXV745jcqRB2DGyEkwcm
+MK5p0fATgrpe/7JuMHfRvNNwfzWBzou5a8SuFnsCgYBM+Hlx94ZwO2ySO9juxURG
+0ntBjIUBP79XEI5Lw6omW83KHKB6t+C/I3GvpXgOJhFQr0Ld6dqc21s0k3MgALpD
+ijlXfVnFagLKVYdxJpLzM8lrjC2WzOwzSfxZYRltUli2BE0pqPEGlgtluErCljot
+SPUiyCx0qQANBtg0nPyRLwKBgHt3urT91ekyAxE6KxWI2tBiOlZ+gi27Z375uwe7
+ZVIyY4+isRmoadfLlCKr0TxWnBA5xvsua/JaScn1f887tEHQ5YkGYOc70YmnPDdi
+OypXPalioWTH/NtWTWW0rL+rPmEOZ9qA9XZx3Xoed8WVFaSJSSg7xq99IxJxT+Se
+DjovAoGAPm+Cxt1AQ0f7GDmlRtbgqg3LLHj+WQ3ajbDR9wvw6Z+xfHQjuiWWqgZB
+Jt9B4IpD8OL1sBBBg0oc8p2m3ZlxRAGv+Git8JqMNWqboUX/L90P2PeTla8jcoWD
+i4JOR6CdhU6qpeXm7U1g9JKrorsvIKMZY8yicy7FLVTcRcdjUiA=
+-----END RSA PRIVATE KEY-----
diff --git a/sh/cpUi2Backend.sh b/sh/cpUi2Backend.sh
new file mode 100755
index 0000000..386ff40
--- /dev/null
+++ b/sh/cpUi2Backend.sh
@@ -0,0 +1,2 @@
+tar zcvf backend.tar.gz ../ui2/backend/*.js ../ui2/backend/package.json
+scp backend.tar.gz pi@192.168.6.103:/home/pi
diff --git a/sh/cyclicRun.sh b/sh/cyclicRun.sh
new file mode 100644
index 0000000..8793794
--- /dev/null
+++ b/sh/cyclicRun.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+for i in $(seq 1 1 $1)
+do
+ echo "cyclic run $i times"
+ node $2
+done
diff --git a/sh/for_recipe.bat b/sh/for_recipe.bat
new file mode 100644
index 0000000..a22c6cc
--- /dev/null
+++ b/sh/for_recipe.bat
@@ -0,0 +1,8 @@
+@echo off
+
+for /l %%x in (1, 1, %1) do (
+ echo %%x
+ node test.js
+)
+
+pause
\ No newline at end of file
diff --git a/sh/rotateTouch.sh b/sh/rotateTouch.sh
index c983e2a..f4ba0e9 100644
--- a/sh/rotateTouch.sh
+++ b/sh/rotateTouch.sh
@@ -1 +1,3 @@
-DISPLAY=:0 xinput --set-prop 'FT5406 memory based driver' 'Coordinate Transformation Matrix' 0 -1 1 1 0 0 0 0 1
\ No newline at end of file
+DISPLAY=:0 xinput --set-prop 'FT5406 memory based driver' 'Coordinate Transformation Matrix' 0 -1 1 1 0 0 0 0 1
+
+DISPLAY=:0 xinput --set-prop 'ILITEK Multi-Touch-V3000' 'Coordinate Transformation Matrix' -1 0 1 0 -1 1 0 0 1
\ No newline at end of file
diff --git a/system/A4988.js b/system/A4988.js
deleted file mode 100644
index cba9e3a..0000000
--- a/system/A4988.js
+++ /dev/null
@@ -1,178 +0,0 @@
-const Gpio = require("pigpio").Gpio;
-
-class A4988 {
- constructor({
- step = 15,
- dir = 14,
- ms1 = 24,
- ms2 = 23,
- ms3 = 18,
- enable = 25
- }) {
- this._abort = false;
- this._delay = 1;
- this._direction = false;
- this._steps = 0;
- this._step_size = "FULL";
- this._enabled = true;
- this._turning = false;
-
- this._step = new Gpio(step, { mode: Gpio.OUTPUT });
- this._dir = new Gpio(dir, { mode: Gpio.OUTPUT });
- this._step.digitalWrite(false);
- this._dir.digitalWrite(false);
-
- if (ms1 && ms2 && ms3) {
- this._ms1 = new Gpio(ms1, { mode: Gpio.OUTPUT });
- this._ms2 = new Gpio(ms2, { mode: Gpio.OUTPUT });
- this._ms3 = new Gpio(ms3, { mode: Gpio.OUTPUT });
-
- this._ms1.digitalWrite(false);
- this._ms2.digitalWrite(false);
- this._ms3.digitalWrite(false);
- }
-
- if (enable) {
- this._enable = new Gpio(enable, { mode: Gpio.OUTPUT });
- this._enable.digitalWrite(false);
- }
- }
-
- get delay() {
- return this._delay;
- }
-
- set delay(d) {
- if (typeof d != "number") throw `'delay' must be a number (${d})`;
- if (d <= 0) throw `'delay' must be >= 0 (${d})`;
- this._delay = d;
- }
-
- get direction() {
- return this._direction;
- }
-
- set direction(d) {
- if (typeof d != "boolean") throw `'direction' must be boolean (${d})`;
- this._direction = d;
- this._dir.digitalWrite(d);
- }
-
- get step_size() {
- return this._step_size;
- }
-
- set step_size(ss) {
- if (!this._ms1) return;
- if (typeof ss != "string") throw `'step_size' must be a string (${ss})`;
- switch (ss.toUpperCase()) {
- case "FULL":
- this._ms1.digitalWrite(false);
- this._ms2.digitalWrite(false);
- this._ms3.digitalWrite(false);
- this._step_size = "FULL";
- break;
- case "HALF":
- this._ms1.digitalWrite(true);
- this._ms2.digitalWrite(false);
- this._ms3.digitalWrite(false);
- this._step_size = "HALF";
- break;
- case "QUARTER":
- this._ms1.digitalWrite(false);
- this._ms2.digitalWrite(true);
- this._ms3.digitalWrite(false);
- this._step_size = "QUARTER";
- break;
- case "EIGHTH":
- this._ms1.digitalWrite(true);
- this._ms2.digitalWrite(true);
- this._ms3.digitalWrite(false);
- this._step_size = "EIGHTH";
- break;
- case "SIXTEENTH":
- this._ms1.digitalWrite(true);
- this._ms2.digitalWrite(true);
- this._ms3.digitalWrite(true);
- this._step_size = "SIXTEENTH";
- break;
- default:
- break;
- }
- }
-
- get enabled() {
- return this._enabled;
- }
-
- set enabled(e) {
- if (e) {
- this._enable.digitalWrite(false);
- this._enabled = true;
- } else {
- this._enable.digitalWrite(true);
- this._enabled = false;
- }
- }
-
- get turning() {
- return this._turning;
- }
-
- enable() {
- this._enable.digitalWrite(false);
- this._enabled = true;
- return new Promise(res => setTimeout(res, 5));
- }
-
- disable() {
- this._enable.digitalWrite(true);
- this._enabled = false;
- return new Promise(res => setTimeout(res, 5));
- }
-
- _turn(steps, res) {
- if (this._abort) {
- this._turning = false;
- res(this._steps);
- return;
- }
- if (this._steps < steps) {
- this._steps++;
- } else {
- this._steps--;
- }
- this._step.digitalWrite(true);
- this._step.digitalWrite(false);
- if (this._steps == steps) {
- this._turning = false;
- res(this._steps);
- return;
- }
- setTimeout(() => this._turn(steps, res), this._delay);
- }
-
- turn(steps = 1, callback) {
- if (this._turning)
- return Promise.reject(new Error("Motor already running"));
- this._steps = 0;
- this._abort = false;
- this._turning = true;
- if (this._steps < steps) {
- this._dir.digitalWrite(true);
- } else {
- this._dir.digitalWrite(false);
- }
- if (typeof callback == "function") {
- this._turn(steps, callback);
- } else {
- return new Promise(res => this._turn(steps, res));
- }
- }
-
- stop() {
- this._abort = true;
- }
-}
-
-module.exports = A4988;
diff --git a/system/index.js b/system/index.js
deleted file mode 100644
index cfbfd40..0000000
--- a/system/index.js
+++ /dev/null
@@ -1,151 +0,0 @@
-const mqtt = require("mqtt");
-const gpio = require("rpi-gpio");
-const A4988 = require("./A4988");
-
-const opt = {
- port: 1883,
- clientId: "cakeVendingSys"
-};
-
-const coinPinIdx = 7; //GPIO 4, pin 7
-const coinEnablePinIdx = 11; //GPIO 17, pin 11
-const kanbanEnablePinIdx = 13; //GPIO 27, pin 13
-const gateLimitPinIdx = 15; //GPIO 22, pin 15
-
-const gateMotor = new A4988({
- step: 24, //GPIO 24, pin 18
- dir: 25, //GPIO 25, pin 22
- ms1: 15, //GPIO 15, pin 10
- ms2: 18, //GPIO 18, pin 12
- ms3: 23, //GPIO 23, pin 16
- enable: 14 //GPIO 14, pin 8
-});
-gateMotor.step_size = "sixteenth";
-
-const gateOpen = -4000;
-const gateClose = 4000;
-
-let coinCnt = 0;
-let coinEnable = false;
-let coinValue = false;
-let coinLastValue = false;
-const coinValueDebounceLimit = 0;
-let coinValueDebounceCnt = 0;
-
-const gateLimitDebounceLimit = 5;
-let gateLimitDebounceCnt = 0;
-let gateLimitValue = false;
-let gateLimitLastValue = false;
-
-console.log(opt.clientId + " started");
-
-gpio.on("change", function(channel, value) {
- // console.log("pin " + channel + " is " + value);
- //if (coinEnable) {
- if (channel === coinPinIdx) {
- if (value === true) {
- if (coinValueDebounceCnt < coinValueDebounceLimit) {
- coinValueDebounceCnt = coinValueDebounceCnt + 1;
- } else {
- coinValue = true;
- coinValueDebounceCnt = 0;
- }
- } else {
- coinValue = false;
- coinValueDebounceCnt = 0;
- }
- //if (coinValue === true && coinLastValue === false) {
- if (value === true) {
- coinCnt = coinCnt + 1;
- console.log(coinCnt);
- client.publish("coin/status/inc", "1");
- if (coinCnt >= 5) {
- coinEnable = false;
- coinCnt = 0;
- gpio.write(coinEnablePinIdx, false);
- console.log("coin disable");
- }
- }
- coinLastValue = coinValue;
- }
- //}
- if (channel === gateLimitPinIdx) {
- if (value === true) {
- if (gateLimitDebounceCnt < gateLimitDebounceLimit) {
- gateLimitDebounceCnt = gateLimitDebounceCnt + 1;
- } else {
- gateLimitValue = true;
- gateLimitDebounceCnt = 0;
- }
- } else {
- gateLimitValue = false;
- gateLimitDebounceCnt = 0;
- }
- if (gateLimitValue === true && gateLimitLastValue === false) {
- gateMotor.stop();
- console.log("gate stoped");
- }
- gateLimitLastValue = gateLimitValue;
- }
-});
-
-const client = mqtt.connect("mqtt://localhost", opt);
-
-client.on("connect", function() {
- console.log("connect to broker OK");
- client.subscribe("coin/cmd/#");
- client.subscribe("kanban/cmd/#");
- client.subscribe("gate/cmd/#");
- gateMotor.turn(gateClose);
-});
-
-client.on("message", function(topic, message) {
- if (topic === "coin/cmd/enable") {
- if (message.toString() === "true") {
- coinEnable = true;
- gpio.write(coinEnablePinIdx, true);
- console.log("coin/cmd/enable true");
- }
- } else if (topic === "kanban/cmd/enable") {
- if (message.toString() === "true") {
- gpio.write(kanbanEnablePinIdx, true);
- console.log("kanban/cmd/enable true");
- } else {
- gpio.write(kanbanEnablePinIdx, false);
- console.log("kanban/cmd/enable false");
- }
- } else if (topic === "gate/cmd/open") {
- if (message.toString() === "true") {
- gateMotor.enable().then(
- gateMotor.turn(gateOpen).then(steps => {
- console.log(`gate turned ${steps} steps`);
- gateMotor.disable();
- })
- );
- console.log("gate/cmd/open true");
- } else {
- gateMotor.enable().then(
- gateMotor.turn(gateClose).then(steps => {
- console.log(`gate turned ${steps} steps`);
- gateMotor.disable();
- })
- );
- console.log("gate/cmd/open false");
- }
- } else if (topic === "gate/cmd/stop") {
- if (message.toString() === "true") {
- gateMotor.stop();
- gateMotor.disable();
- console.log("gate/cmd/stop true");
- }
- }
-});
-
-gpio.setup(coinEnablePinIdx, gpio.DIR_OUT, function(err) {
- gpio.write(coinEnablePinIdx, false);
-});
-gpio.setup(kanbanEnablePinIdx, gpio.DIR_OUT, function(err) {
- gpio.write(kanbanEnablePinIdx, false);
-});
-gpio.setup(coinPinIdx, gpio.DIR_IN, gpio.EDGE_RISING);
-gpio.setup(gateLimitPinIdx, gpio.DIR_IN, gpio.EDGE_RISING);
diff --git a/system/index2.js b/system/index2.js
deleted file mode 100644
index 66095e0..0000000
--- a/system/index2.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const mqtt = require("mqtt");
-const gpio = require("rpi-gpio");
-const A4988 = require("./A4988");
-
-const opt = {
- port: 1883,
- clientId: "cakeVendingSys"
-};
-
-const coinPinIdx = 7; //GPIO 4, pin 7
-const coinEnablePinIdx = 11; //GPIO 17, pin 11
-const kanbanEnablePinIdx = 13; //GPIO 27, pin 13
-
-const gateMotor = new A4988({
- step: 24, //GPIO 24, pin 18
- dir: 25, //GPIO 25, pin 22
- ms1: 15, //GPIO 15, pin 10
- ms2: 18, //GPIO 18, pin 12
- ms3: 23, //GPIO 23, pin 16
- enable: 14 //GPIO 14, pin 8
-});
-gateMotor.step_size = "sixteenth";
-
-const gateOpen = 1000;
-const gateClose = -1000;
-
-let coinCnt = 0;
-let coinEnable = false;
-
-console.log(opt.clientId + " started");
-
-gpio.on("change", function(channel, value) {
- // console.log("pin " + channel + " is " + value);
- if (coinEnable) {
- if (channel === coinPinIdx && value === true) {
- coinCnt = coinCnt + 1;
- console.log(coinCnt);
- client.publish("coin/status/inc", "1")
\ No newline at end of file
diff --git a/system/package.json b/system/package.json
deleted file mode 100644
index 5ac3080..0000000
--- a/system/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "system",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "start": "node index.js",
- "pkg": "pkg index.js -o system -t node8-linux-armv7"
- },
- "bin": "index.js",
- "author": "",
- "license": "ISC",
- "dependencies": {
- "mqtt": "^3.0.0",
- "rpi-gpio": "^2.1.5"
- }
-}
diff --git a/ui2/backend/index.js b/ui2/backend/index.js
index cbe7dbb..2f18368 100644
--- a/ui2/backend/index.js
+++ b/ui2/backend/index.js
@@ -1,7 +1,6 @@
const express = require("express");
const app = express();
const http = require("http");
-const https = require("https");
const cors = require("cors");
const bodyParser = require("body-parser");
const fs = require("fs");
@@ -11,23 +10,13 @@ const mqtt = require("mqtt");
// const A4988 = require("./A4988");
const morgan = require("morgan");
const jwt = require("express-jwt");
-const config = require("./config");
+const config = require("../../config");
+const sqlite3 = require("sqlite3").verbose();
+const os = require("os");
const mqttOpt = {
port: config.mqttBrokerPort,
- clientId: config.apiServerVersion
-};
-const hskey = fs.readFileSync(
- "../../ssl_auth_files/pillaAuth-key.pem",
- "utf-8"
-);
-const hscert = fs.readFileSync(
- "../../ssl_auth_files/pillaAuth-cert.pem",
- "utf-8"
-);
-const credentials = {
- key: hskey,
- cert: hscert
+ clientId: config.backendVersion,
};
const coinPinIdx = 7; //GPIO 4, pin 7
@@ -41,7 +30,7 @@ const gateLimitPinIdx = 15; //GPIO 22, pin 15
// ms1: 15, //GPIO 15, pin 10
// ms2: 18, //GPIO 18, pin 12
// ms3: 23, //GPIO 23, pin 16
-// enable: 14 //GPIO 14, pin 8
+// enable: 14, //GPIO 14, pin 8
// });
// gateMotor.step_size = "sixteenth";
@@ -62,6 +51,8 @@ let gateLimitLastValue = false;
const mqttClient = mqtt.connect("mqtt://localhost", mqttOpt);
+const iNameList = os.networkInterfaces();
+
console.log(mqttOpt.clientId + " started");
app.use(cors());
@@ -70,51 +61,71 @@ app.use(bodyParser.json());
app.use(morgan("dev"));
app.get("/version", (req, res) => {
- res.send(config.apiServerVersion);
+ res.send(config.backendVersion);
});
app.post("/recipe/start/original", (req, res) => {
- if (req.protocol === "http") {
- // exec("node /home/pi/recipe/original.js", function(err, stdout, stderr) {
- // console.log(req.body.cmd);
- // res.send(stdout);
- // });
- res.send("OK");
- }
+ exec("node /home/pi/recipe/original.js", function (err, stdout, stderr) {
+ console.log(req.body.cmd);
+ res.send(stdout);
+ });
+ res.sendStatus(200);
});
app.get("/ad/playList", (req, res) => {
- if (req.protocol === "http") {
- let readDir = fs.readdirSync("/home/guesswho/Downloads");
- res.send(readDir);
- }
+ let readDir = fs.readdirSync("/home/guesswho/Downloads");
+ res.send(readDir);
});
app.post(
"/shutdown",
jwt({ subject: config.subject, name: config.name, secret: config.secret }),
(req, res) => {
- if (req.protocol === "https") {
- res.status(200).send("ok");
- } else {
- res.status(404).send("not found");
- }
+ res.sendStatus(200);
}
);
-http.createServer(app).listen(config.httpApiServerPort, "localhost", () => {
- console.log(
- "Express http server listening on port " + config.httpApiServerPort
- );
+http.createServer(app).listen(config.backendPort, "localhost", () => {
+ console.log("backend listening on port " + config.backendPort);
});
-https.createServer(credentials, app).listen(config.httpsApiServerPort, () => {
- console.log(
- "Express https server listening on port " + config.httpsApiServerPort
- );
+http
+ .createServer(app)
+ .listen(config.backendPort, iNameList.tun0[0].address, () => {
+ console.log(
+ iNameList.tun0[0].address +
+ " " +
+ config.backendVersion +
+ " listening on port " +
+ config.backendPort
+ );
+ });
+
+let db = new sqlite3.Database("mydatebase.db", function (err) {
+ if (err) throw err;
});
-// gpio.on("change", function(channel, value) {
+db.serialize(function () {
+ //db.run 如果 Staff 資料表不存在,那就建立 Staff 資料表
+ db.run("CREATE TABLE IF NOT EXISTS Stuff (thing TEXT)");
+ let stmt = db.prepare("INSERT INTO Stuff VALUES (?)");
+
+ //寫進10筆資料
+ for (var i = 0; i < 10; i++) {
+ stmt.run("staff_number" + i);
+ }
+
+ stmt.finalize();
+
+ db.each("SELECT rowid AS id, thing FROM Stuff", function (err, row) {
+ //log 出所有的資料
+ console.log(row.id + ": " + row.thing);
+ });
+});
+
+db.close();
+
+// gpio.on("change", function (channel, value) {
// // console.log("pin " + channel + " is " + value);
// //if (coinEnable) {
// if (channel === coinPinIdx) {
@@ -164,15 +175,15 @@ https.createServer(credentials, app).listen(config.httpsApiServerPort, () => {
// }
// });
-// mqttClient.on("connect", function() {
-// console.log("connect to broker OK");
-// mqttClient.subscribe("coin/cmd/#");
-// mqttClient.subscribe("kanban/cmd/#");
-// mqttClient.subscribe("gate/cmd/#");
-// gateMotor.turn(gateClose);
-// });
+mqttClient.on("connect", function () {
+ console.log("connect to broker OK");
+ mqttClient.subscribe("coin/cmd/#");
+ mqttClient.subscribe("kanban/cmd/#");
+ mqttClient.subscribe("gate/cmd/#");
+ // gateMotor.turn(gateClose);
+});
-// mqttClient.on("message", function(topic, message) {
+// mqttClient.on("message", function (topic, message) {
// if (topic === "coin/cmd/enable") {
// if (message.toString() === "true") {
// coinEnable = true;
@@ -190,7 +201,7 @@ https.createServer(credentials, app).listen(config.httpsApiServerPort, () => {
// } else if (topic === "gate/cmd/open") {
// if (message.toString() === "true") {
// gateMotor.enable().then(
-// gateMotor.turn(gateOpen).then(steps => {
+// gateMotor.turn(gateOpen).then((steps) => {
// console.log(`gate turned ${steps} steps`);
// gateMotor.disable();
// })
@@ -198,7 +209,7 @@ https.createServer(credentials, app).listen(config.httpsApiServerPort, () => {
// console.log("gate/cmd/open true");
// } else {
// gateMotor.enable().then(
-// gateMotor.turn(gateClose).then(steps => {
+// gateMotor.turn(gateClose).then((steps) => {
// console.log(`gate turned ${steps} steps`);
// gateMotor.disable();
// })
@@ -214,10 +225,10 @@ https.createServer(credentials, app).listen(config.httpsApiServerPort, () => {
// }
// });
-// gpio.setup(coinEnablePinIdx, gpio.DIR_OUT, function(err) {
+// gpio.setup(coinEnablePinIdx, gpio.DIR_OUT, function (err) {
// gpio.write(coinEnablePinIdx, false);
// });
-// gpio.setup(kanbanEnablePinIdx, gpio.DIR_OUT, function(err) {
+// gpio.setup(kanbanEnablePinIdx, gpio.DIR_OUT, function (err) {
// gpio.write(kanbanEnablePinIdx, false);
// });
// gpio.setup(coinPinIdx, gpio.DIR_IN, gpio.EDGE_RISING);
diff --git a/ui2/backend/mydatebase.db b/ui2/backend/mydatebase.db
new file mode 100644
index 0000000..38f4de2
Binary files /dev/null and b/ui2/backend/mydatebase.db differ
diff --git a/ui2/frontend/package.json b/ui2/frontend/package.json
index 39ad54e..addd7cf 100644
--- a/ui2/frontend/package.json
+++ b/ui2/frontend/package.json
@@ -1,5 +1,5 @@
{
- "name": "ui2",
+ "name": "cake_vending_frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
diff --git a/ui2/frontend/public/index.html b/ui2/frontend/public/index.html
index 4ecacc9..6cfc56f 100644
--- a/ui2/frontend/public/index.html
+++ b/ui2/frontend/public/index.html
@@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
- easytp
+ cake vending frontend