new file: .gitignore
new file: main.js new file: package-lock.json new file: package.json
This commit is contained in:
136
.gitignore
vendored
Normal file
136
.gitignore
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# 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
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://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/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# vitepress build output
|
||||
**/.vitepress/dist
|
||||
|
||||
# vitepress cache directory
|
||||
**/.vitepress/cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
261
main.js
Normal file
261
main.js
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
QR code server protocol:
|
||||
https://macro-deck.app/quick-setup/
|
||||
+
|
||||
{"instanceName":"DESKTOP-J09EM3G","networkInterfaces":["192.168.1.134"],"port":8191,"ssl":false,"token":"vPl4Vq7v"} in base64
|
||||
=
|
||||
https://macro-deck.app/quick-setup/eyJpbnN0YW5jZU5hbWUiOiJERVNLVE9QLUowOUVNM0ciLCJuZXR3b3JrSW50ZXJmYWNlcyI6WyIxOTIuMTY4LjEuMTM0Il0sInBvcnQiOjgxOTEsInNzbCI6ZmFsc2UsInRva2VuIjoidlBsNFZxN3YifQ==
|
||||
|
||||
Device types: Web - Android
|
||||
Newer android app (3.3.0) identifies as web (no device settings control)
|
||||
Github version (2.4.1-beta) identifies as Android (brightness, auto-connection,keep awake contrll)
|
||||
|
||||
Start WebSocket server
|
||||
Server broadcasts connection data via UDP: {"computer-name": "MDServer","ip-address": "192.168.1.133","port": 8191}
|
||||
Client gets
|
||||
|
||||
Client connects to websocket server
|
||||
Client sends: {"Method": "CONNECTED","Client-Id": "CLIENTNAME","API": "20","Device-Type": "Android"}
|
||||
Server responds with: {"Method": "GET_CONFIG","Rows": 2,"Columns": 2,"ButtonSpacing": 10,"ButtonRadius": 10,"ButtonBackground": true,"Brightness": 0.3,"AutoConnect": false,"WakeLock": "Connected","SupportButtonReleaseLongPress": true}
|
||||
Client sends: {Method: 'GET_BUTTONS'}
|
||||
Server responds with: {"Method": "GET_BUTTONS","Buttons": [{"IconBase64": "","Position_X": 0,"Position_Y": 0,"LabelBase64": "","BackgroundColorHex": "#232323"}]}
|
||||
Client sends on button press: { "Method": "BUTTON_PRESS", "Message": "0_0" } (X_Y)
|
||||
Server can respond with single button updates: {"Method": "UPDATE_BUTTON","Buttons": [{"IconBase64": "","Position_X": 0,"Position_Y": 0,"LabelBase64": "","BackgroundColorHex": "#000000"}]}
|
||||
|
||||
- Server can resend "GET_BUTTONS" at any moment to update setup
|
||||
- Server can resend "GET_CONFIG" at any moment to control client
|
||||
- Server can "UPDATE_BUTTON" in any moment
|
||||
*/
|
||||
|
||||
var clients = {}
|
||||
|
||||
function generateQR(ServerName, ServerIP, token, ServerPort = 8191) {
|
||||
const qrcode = require('qrcode-terminal');
|
||||
// it generates the exact same link as the official one, but it does not work (?)
|
||||
var obj = {
|
||||
"instanceName": ServerName,
|
||||
"networkInterfaces": ServerIP,
|
||||
"port": ServerPort,
|
||||
"ssl": false,
|
||||
"token": token
|
||||
}
|
||||
var url = "https://macro-deck.app/quick-setup/" + Buffer.from(JSON.stringify(obj)).toString('base64');
|
||||
console.log(url)
|
||||
qrcode.generate(url, { small: true }, function (qrcode) {
|
||||
console.log(qrcode);
|
||||
});
|
||||
}
|
||||
|
||||
function broadcastServer(ServerName, ServerIP, BroadcastPort = 8191, BroadcastAddress = '255.255.255.255') {
|
||||
const dgram = require('dgram');
|
||||
const udpClient = dgram.createSocket('udp4');
|
||||
|
||||
udpClient.bind(() => {
|
||||
udpClient.setBroadcast(true);
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
try {
|
||||
const broadcastObject = {
|
||||
"computer-name": ServerName,
|
||||
"ip-address": ServerIP,
|
||||
"port": BroadcastPort
|
||||
};
|
||||
|
||||
const message = Buffer.from(JSON.stringify(broadcastObject));
|
||||
udpClient.send(message, 0, message.length, BroadcastPort, BroadcastAddress, (err) => {
|
||||
if (err) console.error(err);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function startWsServer(ServerPort = 8191) {
|
||||
const { WebSocketServer } = require("ws");
|
||||
const wss = new WebSocketServer({ port: ServerPort })
|
||||
wss.on('connection', function connection(ws, req) {
|
||||
const ip = req.socket.remoteAddress;
|
||||
ws.on('error', console.error)
|
||||
ws.on('message', function message(data) {
|
||||
data = JSON.parse(data)
|
||||
console.log(ip, data);
|
||||
switch (data.Method) {
|
||||
case "CONNECTED":
|
||||
clients[data["Client-Id"]] = ip.replace("::ffff:", "");
|
||||
//on "CONNECTED" request, send the grid setup, and client settings
|
||||
var obj = JSON.stringify({
|
||||
"Method": "GET_CONFIG",
|
||||
"Rows": 6,
|
||||
"Columns": 8,
|
||||
"ButtonSpacing": 2,
|
||||
"ButtonRadius": 10,
|
||||
"ButtonBackground": true,
|
||||
"Brightness": 0.5, // 0.1 -> 1.0
|
||||
"AutoConnect": true, // true - false
|
||||
"WakeLock": "Connected", //Never - Connected - Always
|
||||
"SupportButtonReleaseLongPress": true
|
||||
})
|
||||
ws.send(obj);
|
||||
break;
|
||||
|
||||
case "GET_BUTTONS":
|
||||
//Client will request the buttons content and their position in the setup
|
||||
var obj = JSON.stringify({
|
||||
"Method": "GET_BUTTONS",
|
||||
"Buttons": [
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 1,
|
||||
"Position_Y": 0,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#232323"
|
||||
},
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 0,
|
||||
"Position_Y": 0,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#232323"
|
||||
},
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 1,
|
||||
"Position_Y": 1,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#232323"
|
||||
},
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 0,
|
||||
"Position_Y": 1,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#232323"
|
||||
}
|
||||
]
|
||||
})
|
||||
ws.send(obj);
|
||||
break;
|
||||
case "BUTTON_PRESS":
|
||||
var obj = JSON.stringify({
|
||||
"Method": "UPDATE_BUTTON",
|
||||
"Buttons": [
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 0,
|
||||
"Position_Y": 0,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#000000"
|
||||
}
|
||||
]
|
||||
})
|
||||
// broadcast update to all clients
|
||||
wss.clients.forEach(function each(client) {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(obj);
|
||||
}
|
||||
});
|
||||
var obj = JSON.stringify({
|
||||
"Method": "UPDATE_BUTTON",
|
||||
"Buttons": [
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 7,
|
||||
"Position_Y": 5,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#000000"
|
||||
}
|
||||
]
|
||||
})
|
||||
wss.clients.forEach(function each(client) {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(obj);
|
||||
}
|
||||
});
|
||||
|
||||
//ws.send(obj)
|
||||
console.log(data.Method, data.Message.split('_'))
|
||||
break;
|
||||
case "BUTTON_RELEASE":
|
||||
var obj = JSON.stringify({
|
||||
"Method": "UPDATE_BUTTON",
|
||||
"Buttons": [
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 0,
|
||||
"Position_Y": 0,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
})
|
||||
wss.clients.forEach(function each(client) {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(obj);
|
||||
}
|
||||
});
|
||||
var obj = JSON.stringify({
|
||||
"Method": "UPDATE_BUTTON",
|
||||
"Buttons": [
|
||||
{
|
||||
"IconBase64": "",
|
||||
"Position_X": 7,
|
||||
"Position_Y": 5,
|
||||
"LabelBase64": "",
|
||||
"BackgroundColorHex": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
})
|
||||
wss.clients.forEach(function each(client) {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(obj);
|
||||
}
|
||||
});
|
||||
//ws.send(obj);
|
||||
console.log(data.Method, data.Message.split('_'))
|
||||
break;
|
||||
case "BUTTON_LONG_PRESS":
|
||||
console.log(data.Method, data.Message.split('_'))
|
||||
break;
|
||||
case "BUTTON_LONG_PRESS_RELEASE":
|
||||
console.log(data.Method, data.Message.split('_'))
|
||||
break;
|
||||
default:
|
||||
console.log(data);
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function startWsClient(ip, port = 8191) {
|
||||
const WebSocket = require("ws");
|
||||
const fs = require("fs");
|
||||
const ws = new WebSocket("ws://" + ip + ":" + port);
|
||||
ws.on('error', console.error);
|
||||
|
||||
ws.on('open', function open() {
|
||||
|
||||
var obj = JSON.stringify({
|
||||
"Method": "CONNECTED",
|
||||
"Client-Id": "LinuxClient",
|
||||
"API": "20",
|
||||
"Device-Type": "Android" //Web - Android
|
||||
});
|
||||
ws.send(obj);
|
||||
});
|
||||
var logs = { data: [] }
|
||||
ws.on('message', function message(data) {
|
||||
console.log('received: %s', data);
|
||||
//logs.data.push(JSON.parse(data));
|
||||
//fs.writeFileSync("test.json", JSON.stringify(logs), 'utf8', null);
|
||||
});
|
||||
}
|
||||
|
||||
//generateQR("DESKTOP-J09EM3G", ["192.168.1.134"], "vPl4Vq7v");
|
||||
//startWsClient("192.168.1.134");
|
||||
|
||||
broadcastServer("DEBIAN-PC", "192.168.1.133");
|
||||
|
||||
startWsServer();
|
||||
46
package-lock.json
generated
Normal file
46
package-lock.json
generated
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "macrodeckreimp",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "macrodeckreimp",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode-terminal": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz",
|
||||
"integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==",
|
||||
"bin": {
|
||||
"qrcode-terminal": "bin/qrcode-terminal.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "macrodeckreimp",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"qrcode-terminal": "^0.12.0",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user