new file: .gitignore

new file:   main.js
	new file:   package-lock.json
	new file:   package.json
This commit is contained in:
2025-02-02 17:30:09 -03:00
commit 160efe6906
4 changed files with 458 additions and 0 deletions

136
.gitignore vendored Normal file
View 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
View 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
View 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
View 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"
}
}