mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-01-29 10:09:11 +03:00
Merge branch 'dev'
This commit is contained in:
4
mock-api/.gitattributes
vendored
4
mock-api/.gitattributes
vendored
@@ -1,4 +0,0 @@
|
||||
/.yarn/** linguist-vendored
|
||||
/.yarn/releases/* binary
|
||||
/.yarn/plugins/**/* binary
|
||||
/.pnp.* binary linguist-generated
|
||||
935
mock-api/.yarn/releases/yarn-4.7.0.cjs
vendored
935
mock-api/.yarn/releases/yarn-4.7.0.cjs
vendored
File diff suppressed because one or more lines are too long
@@ -1,3 +0,0 @@
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.7.0.cjs
|
||||
@@ -3,10 +3,11 @@ When developing and testing the web interface, it's handy not to bother with re-
|
||||
# prerequisites
|
||||
|
||||
- Install the latest LTS of NodeJS
|
||||
- Install yarn (`npm install -g yarn`)
|
||||
- install corepack `npm install -g corepack@latest` and `orepack enable`
|
||||
- Install pnpm (`corepack use pnpm@latest-10` on linux or `winget install -e --id pnpm.pnpm` on windows). See <https://pnpm.io/installation>
|
||||
- Install bun (<https://bun.sh/docs/installation>)
|
||||
- type `yarn` from this `mock-api` folder to build
|
||||
- type `pnpm install` from this `mock-api` folder to build
|
||||
|
||||
# To run
|
||||
|
||||
- `yarn standalone` from the main `interface` folder and then navigate to <http://localhost:3000>
|
||||
- `pnpm standalone` from the main `interface` folder and then navigate to <http://localhost:3000>
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
// used to simulate
|
||||
// - file uploads
|
||||
// - EventSource (SSE) for log messages
|
||||
// Mock server for development
|
||||
// Simulates file uploads and EventSource (SSE) for log messages
|
||||
import formidable from 'formidable';
|
||||
|
||||
function pad(number) {
|
||||
let r = String(number);
|
||||
if (r.length === 1) {
|
||||
r = '0' + r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
// Constants reused across requests
|
||||
const VALID_EXTENSIONS = new Set(['bin', 'json', 'md5']);
|
||||
const ONE_SECOND_MS = 1000;
|
||||
const TEN_PERCENT = 10;
|
||||
|
||||
// e.g. 2024-03-29 07:02:37.856
|
||||
Date.prototype.toISOString = function () {
|
||||
return (
|
||||
this.getUTCFullYear() +
|
||||
'-' +
|
||||
pad(this.getUTCMonth() + 1) +
|
||||
'-' +
|
||||
pad(this.getUTCDate()) +
|
||||
' ' +
|
||||
pad(this.getUTCHours()) +
|
||||
':' +
|
||||
pad(this.getUTCMinutes()) +
|
||||
':' +
|
||||
pad(this.getUTCSeconds()) +
|
||||
'.' +
|
||||
String((this.getUTCMilliseconds() / 1000).toFixed(3)).slice(2, 5)
|
||||
// padding function
|
||||
const pad = (number) => String(number).padStart(2, '0');
|
||||
|
||||
// Simple throttle helper (time-based)
|
||||
const throttle = (fn, intervalMs) => {
|
||||
let last = 0;
|
||||
return (...args) => {
|
||||
const now = Date.now();
|
||||
if (now - last >= intervalMs) {
|
||||
last = now;
|
||||
fn(...args);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Cached date formatter to avoid prototype pollution
|
||||
const formatDate = (date) => {
|
||||
const year = date.getUTCFullYear();
|
||||
const month = pad(date.getUTCMonth() + 1);
|
||||
const day = pad(date.getUTCDate());
|
||||
const hours = pad(date.getUTCHours());
|
||||
const minutes = pad(date.getUTCMinutes());
|
||||
const seconds = pad(date.getUTCSeconds());
|
||||
const milliseconds = String((date.getUTCMilliseconds() / 1000).toFixed(3)).slice(
|
||||
2,
|
||||
5
|
||||
);
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
|
||||
};
|
||||
|
||||
export default () => {
|
||||
@@ -35,97 +43,174 @@ export default () => {
|
||||
name: 'vite:mockserver',
|
||||
configureServer: async (server) => {
|
||||
server.middlewares.use(async (req, res, next) => {
|
||||
// catch any file uploads
|
||||
// Handle file uploads
|
||||
if (req.url.startsWith('/rest/uploadFile')) {
|
||||
// show progress
|
||||
let progress = 0;
|
||||
const file_size = req.headers['content-length'];
|
||||
console.log('File size: ' + file_size);
|
||||
req.on('data', async (chunk) => {
|
||||
progress += chunk.length;
|
||||
const percentage = (progress / file_size) * 100;
|
||||
console.log(`Progress: ${Math.round(percentage)}%`);
|
||||
// await new Promise((resolve) => setTimeout(() => resolve(), 3000)); // slow it down
|
||||
});
|
||||
|
||||
const form = formidable({});
|
||||
let fields;
|
||||
let files;
|
||||
try {
|
||||
[fields, files] = await form.parse(req);
|
||||
} catch (err) {
|
||||
console.error('Not json form content');
|
||||
res.writeHead(err.httpCode || 400, {
|
||||
'Content-Type': 'text/plain'
|
||||
// CORS preflight support
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.writeHead(204, {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Cache-Control',
|
||||
'Access-Control-Max-Age': '600'
|
||||
});
|
||||
res.end(String(err));
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// only process when we have a file
|
||||
if (Object.keys(files).length > 0) {
|
||||
const uploaded_file = files.file[0];
|
||||
const file_name = uploaded_file.originalFilename;
|
||||
const file_extension = file_name.substring(
|
||||
file_name.lastIndexOf('.') + 1
|
||||
if (req.method !== 'POST') {
|
||||
res.statusCode = 405;
|
||||
res.setHeader('Allow', 'POST, OPTIONS');
|
||||
res.end('Method Not Allowed');
|
||||
return;
|
||||
}
|
||||
|
||||
const fileSize = parseInt(req.headers['content-length'] || '0', 10);
|
||||
let progress = 0;
|
||||
|
||||
// Track upload progress
|
||||
const logThrottled = throttle((percentage) => {
|
||||
console.log(`Upload progress: ${percentage}%`);
|
||||
}, ONE_SECOND_MS);
|
||||
|
||||
req.on('data', (chunk) => {
|
||||
progress += chunk.length;
|
||||
if (fileSize > 0) {
|
||||
const percentage = Math.round((progress / fileSize) * 100);
|
||||
// Only log every ~1s and for meaningful changes (>=10%)
|
||||
if (percentage % TEN_PERCENT === 0) {
|
||||
logThrottled(percentage);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const form = formidable({
|
||||
maxFileSize: 50 * 1024 * 1024, // 50MB limit
|
||||
keepExtensions: true,
|
||||
multiples: false,
|
||||
allowEmptyFiles: false
|
||||
});
|
||||
|
||||
const [fields, files] = await form.parse(req);
|
||||
|
||||
if (Object.keys(files).length === 0) {
|
||||
res.statusCode = 400;
|
||||
res.end('No file uploaded');
|
||||
return;
|
||||
}
|
||||
|
||||
const uploadedFile = Array.isArray(files.file)
|
||||
? files.file[0]
|
||||
: files.file;
|
||||
const fileName = uploadedFile.originalFilename;
|
||||
const fileExtension = fileName
|
||||
.substring(fileName.lastIndexOf('.') + 1)
|
||||
.toLowerCase();
|
||||
|
||||
console.log(
|
||||
`File uploaded: ${fileName} (${fileExtension}, ${fileSize} bytes)`
|
||||
);
|
||||
|
||||
console.log('Filename: ' + file_name);
|
||||
console.log('Extension: ' + file_extension);
|
||||
console.log('File size: ' + file_size);
|
||||
// Validate file extension
|
||||
if (!VALID_EXTENSIONS.has(fileExtension)) {
|
||||
res.statusCode = 406;
|
||||
res.end('Invalid file extension');
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_extension === 'bin' || file_extension === 'json') {
|
||||
console.log('File uploaded successfully!');
|
||||
} else if (file_extension === 'md5') {
|
||||
console.log('MD5 hash generated successfully!');
|
||||
// Handle different file types
|
||||
if (fileExtension === 'md5') {
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(
|
||||
JSON.stringify({
|
||||
md5: 'ef4304fc4d9025a58dcf25d71c882d2c'
|
||||
})
|
||||
);
|
||||
} else {
|
||||
res.statusCode = 406;
|
||||
console.log('Invalid file extension!');
|
||||
console.log('File uploaded successfully!');
|
||||
res.end();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Upload error:', err && err.message ? err.message : err);
|
||||
res.statusCode = err.httpCode || 400;
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.end(err && err.message ? err.message : 'Upload error');
|
||||
}
|
||||
|
||||
res.end();
|
||||
}
|
||||
|
||||
// SSE Eventsource
|
||||
// Handle Server-Sent Events (SSE) for log streaming
|
||||
else if (req.url.startsWith('/es/log')) {
|
||||
// Set SSE headers
|
||||
res.writeHead(200, {
|
||||
Connection: 'keep-alive',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Content-Type': 'text/event-stream'
|
||||
'Cache-Control': 'no-cache, no-transform',
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'Cache-Control',
|
||||
'X-Accel-Buffering': 'no' // disable proxy buffering (nginx, etc.)
|
||||
});
|
||||
|
||||
let count = 0;
|
||||
const interval = setInterval(() => {
|
||||
let message = 'message #' + count;
|
||||
if (count % 6 === 1) {
|
||||
// Flush headers early when supported
|
||||
if (typeof res.flushHeaders === 'function') {
|
||||
res.flushHeaders();
|
||||
}
|
||||
|
||||
let messageCount = 0;
|
||||
const logLevels = [3, 4, 5, 6, 7, 8]; // Different log levels
|
||||
const logNames = ['system', 'ems', 'wifi', 'mqtt', 'ntp', 'api'];
|
||||
|
||||
const sendLogMessage = () => {
|
||||
const level = logLevels[messageCount % logLevels.length];
|
||||
const name = logNames[messageCount % logNames.length];
|
||||
let message = `Log message #${messageCount}`;
|
||||
|
||||
// Add long message every 6th message
|
||||
if (messageCount % 6 === 1) {
|
||||
message +=
|
||||
' that is a long message that will be wrapped, to test if it gets truncated';
|
||||
' - This is a longer message to test text wrapping and truncation behavior in the UI';
|
||||
}
|
||||
const data = {
|
||||
t: new Date().toISOString(),
|
||||
l: 3 + (count % 6),
|
||||
i: count,
|
||||
n: 'system',
|
||||
|
||||
const logData = {
|
||||
t: formatDate(new Date()),
|
||||
l: level,
|
||||
i: messageCount,
|
||||
n: name,
|
||||
m: message
|
||||
};
|
||||
count++;
|
||||
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
||||
}, 1000);
|
||||
|
||||
// if client closes connection
|
||||
res.on('close', () => {
|
||||
console.log('Closing ES connection');
|
||||
clearInterval(interval);
|
||||
res.end();
|
||||
});
|
||||
res.write(`data: ${JSON.stringify(logData)}\n\n`);
|
||||
messageCount++;
|
||||
};
|
||||
|
||||
// Send initial message
|
||||
res.write(`retry: 2000\n\n`); // client reconnection delay
|
||||
sendLogMessage();
|
||||
|
||||
// Set up interval for periodic messages
|
||||
const messageInterval = setInterval(sendLogMessage, 500);
|
||||
if (typeof messageInterval.unref === 'function') messageInterval.unref();
|
||||
|
||||
// Heartbeat to keep connections alive through proxies
|
||||
const heartbeat = setInterval(() => {
|
||||
res.write(`:keep-alive ${Date.now()}\n\n`);
|
||||
}, 15 * ONE_SECOND_MS);
|
||||
if (typeof heartbeat.unref === 'function') heartbeat.unref();
|
||||
|
||||
// Clean up on connection close
|
||||
const cleanup = () => {
|
||||
console.log('SSE connection closed');
|
||||
clearInterval(messageInterval);
|
||||
clearInterval(heartbeat);
|
||||
if (!res.destroyed) {
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
|
||||
res.on('close', cleanup);
|
||||
res.on('error', cleanup);
|
||||
res.on('finish', cleanup);
|
||||
} else {
|
||||
next(); // move on to the next middleware function in chain
|
||||
next(); // Continue to next middleware
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "mock-api",
|
||||
"version": "3.7.2",
|
||||
"version": "3.8.0",
|
||||
"description": "mock api for EMS-ESP",
|
||||
"author": "proddy, emsesp.org",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"mock-rest": "bun --watch rest_server.ts",
|
||||
"mock-rest": "bun --watch restServer.ts",
|
||||
"format": "prettier -l -w '**/*.{ts,tsx,js,css,json,md}'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@msgpack/msgpack": "^3.1.1",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"formidable": "^3.5.2",
|
||||
"itty-router": "^5.0.18",
|
||||
"prettier": "^3.5.3"
|
||||
"@msgpack/msgpack": "^3.1.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.0",
|
||||
"formidable": "^3.5.4",
|
||||
"itty-router": "^5.0.22",
|
||||
"prettier": "^3.7.4"
|
||||
},
|
||||
"packageManager": "yarn@4.7.0"
|
||||
"packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a"
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ let settings = {
|
||||
eth_power: 15,
|
||||
eth_phy_addr: 0,
|
||||
eth_clock_mode: 1,
|
||||
led_type: 0,
|
||||
platform: 'ESP32',
|
||||
modbus_enabled: false,
|
||||
modbus_port: 502,
|
||||
@@ -105,63 +106,93 @@ let system_status = {
|
||||
psram_size: 8189,
|
||||
free_psram: 8166,
|
||||
has_loader: true,
|
||||
has_partition: true,
|
||||
partitions: [
|
||||
{
|
||||
partition: 'app0', // this one is active
|
||||
version: 'XX.XX.XX', // defined later
|
||||
install_date: '2025-03-01T13:29:13.999Z',
|
||||
size: 4672
|
||||
},
|
||||
{
|
||||
partition: 'app1',
|
||||
version: '3.8.1-dev.40',
|
||||
install_date: '2025-03-01T13:29:13.999Z',
|
||||
size: 4672
|
||||
},
|
||||
{
|
||||
partition: 'factory',
|
||||
version: '3.8.1-dev.39',
|
||||
install_date: '2025-03-01T13:29:13.999Z',
|
||||
size: 4672
|
||||
}
|
||||
],
|
||||
// partitions: [],
|
||||
developer_mode: true,
|
||||
model: '',
|
||||
// model: 'BBQKees Electronics EMS Gateway E32 V2 (E32 V2.0 P3/2024011)',
|
||||
// status: 0,
|
||||
status: 3
|
||||
};
|
||||
|
||||
let VERSION_IS_UPGRADEABLE: boolean;
|
||||
|
||||
// Versions
|
||||
// default - on latest stable, no stable upgrades
|
||||
let THIS_VERSION = '3.7.2';
|
||||
let LATEST_STABLE_VERSION = '3.7.2';
|
||||
let LATEST_DEV_VERSION = '3.7.3-dev.9';
|
||||
// Test Versioning
|
||||
let DEV_VERSION_IS_UPGRADEABLE: boolean;
|
||||
let STABLE_VERSION_IS_UPGRADEABLE: boolean;
|
||||
let THIS_VERSION: string;
|
||||
let LATEST_STABLE_VERSION = '3.8.0';
|
||||
let LATEST_DEV_VERSION = '3.8.1-dev.2';
|
||||
|
||||
// scenarios for testing versioning
|
||||
let version_test = 0;
|
||||
version_test = 0; // on latest stable, no upgrades, but can switch
|
||||
// version_test = 1; // on latest dev, no update
|
||||
// version_test = 2; // on stable, upgrade stable to latest stable
|
||||
// version_test = 3; // on dev, upgrade dev to latest dev
|
||||
let version_test = 0; // on latest stable, or switch to dev
|
||||
// let version_test = 1; // on latest dev, or switch back to stable
|
||||
// let version_test = 2; // upgrade an older stable to latest stable or switch to latest dev
|
||||
// let version_test = 3; // upgrade dev to latest, or switch to stable
|
||||
// let version_test = 4; // downgrade to an older dev, or switch back to stable
|
||||
|
||||
switch (version_test as number) {
|
||||
case 0:
|
||||
default:
|
||||
// use default - on latest stable, no upgrades, but can switch
|
||||
VERSION_IS_UPGRADEABLE = false;
|
||||
// on latest stable, or switch to dev
|
||||
THIS_VERSION = LATEST_STABLE_VERSION;
|
||||
STABLE_VERSION_IS_UPGRADEABLE = false;
|
||||
DEV_VERSION_IS_UPGRADEABLE = true;
|
||||
break;
|
||||
case 1:
|
||||
// on latest dev, no update
|
||||
THIS_VERSION = '3.7.2-dev.9';
|
||||
LATEST_STABLE_VERSION = '3.7.2';
|
||||
LATEST_DEV_VERSION = '3.7.3-dev.9';
|
||||
VERSION_IS_UPGRADEABLE = false;
|
||||
// on latest dev, or switch back to stable
|
||||
THIS_VERSION = LATEST_DEV_VERSION;
|
||||
STABLE_VERSION_IS_UPGRADEABLE = false;
|
||||
DEV_VERSION_IS_UPGRADEABLE = false;
|
||||
break;
|
||||
case 2:
|
||||
// upgrade stable to latest stable
|
||||
THIS_VERSION = '3.6.5';
|
||||
LATEST_STABLE_VERSION = '3.7.2';
|
||||
LATEST_DEV_VERSION = '3.7.3-dev.12';
|
||||
VERSION_IS_UPGRADEABLE = true;
|
||||
// upgrade an older stable to latest stable or switch to latest dev
|
||||
THIS_VERSION = '3.8.0';
|
||||
STABLE_VERSION_IS_UPGRADEABLE = true;
|
||||
DEV_VERSION_IS_UPGRADEABLE = true;
|
||||
break;
|
||||
case 3:
|
||||
// upgrade dev to latest dev
|
||||
THIS_VERSION = '3.7.2-dev-1';
|
||||
LATEST_STABLE_VERSION = '3.7.2';
|
||||
LATEST_DEV_VERSION = '3.7.3-dev.12';
|
||||
VERSION_IS_UPGRADEABLE = true;
|
||||
// upgrade dev to latest, or switch to stable
|
||||
THIS_VERSION = '3.8.1-dev.3';
|
||||
STABLE_VERSION_IS_UPGRADEABLE = false;
|
||||
DEV_VERSION_IS_UPGRADEABLE = true;
|
||||
break;
|
||||
case 4:
|
||||
// downgrade to an older dev, or switch back to stable
|
||||
THIS_VERSION = '3.8.1-dev.1';
|
||||
STABLE_VERSION_IS_UPGRADEABLE = true;
|
||||
DEV_VERSION_IS_UPGRADEABLE = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// set the version
|
||||
system_status.emsesp_version = THIS_VERSION;
|
||||
system_status.partitions[0].version = THIS_VERSION; // app0
|
||||
|
||||
const emulate_esp = 'ESP32S3';
|
||||
// const emulate_esp = 'ESP32';
|
||||
// set the ESP platform - using ESP32 will disable OTA and automatic version downloading
|
||||
let emulate_esp: string;
|
||||
emulate_esp = 'ESP32S3';
|
||||
// emulate_esp = 'ESP32';
|
||||
|
||||
switch (emulate_esp as string) {
|
||||
switch (emulate_esp) {
|
||||
// ESP32 4MB
|
||||
case 'ESP32':
|
||||
system_status.esp_platform = 'ESP32';
|
||||
@@ -175,7 +206,7 @@ switch (emulate_esp as string) {
|
||||
settings.platform = 'ESP32';
|
||||
break;
|
||||
|
||||
// ESP32S3
|
||||
// ESP32 S3
|
||||
case 'ESP32S3':
|
||||
default:
|
||||
system_status.esp_platform = 'ESP32S3';
|
||||
@@ -185,7 +216,7 @@ switch (emulate_esp as string) {
|
||||
system_status.psram = true;
|
||||
system_status.psram_size = 8189;
|
||||
system_status.free_psram = 8166;
|
||||
settings.board_profile = 'S3';
|
||||
settings.board_profile = 'S32S3';
|
||||
settings.platform = 'ESP32S3';
|
||||
break;
|
||||
}
|
||||
@@ -269,10 +300,10 @@ function updateMask(entity: any, de: any, dd: any) {
|
||||
const old_custom_name = dd.nodes[dd_objIndex].cn;
|
||||
console.log(
|
||||
'comparing names, old (' +
|
||||
old_custom_name +
|
||||
') with new (' +
|
||||
new_custom_name +
|
||||
')'
|
||||
old_custom_name +
|
||||
') with new (' +
|
||||
new_custom_name +
|
||||
')'
|
||||
);
|
||||
if (old_custom_name !== new_custom_name) {
|
||||
changed = true;
|
||||
@@ -353,7 +384,7 @@ function custom_support() {
|
||||
'',
|
||||
"For help and questions please <a target='_blank' href='https://emsesp.org'>contact</a> your installer."
|
||||
],
|
||||
img_url: 'https://docs.emsesp.org/_media/images/designer.png'
|
||||
img_url: 'https://emsesp.org/_media/images/designer.png'
|
||||
// img_url: 'https://picsum.photos/200/300'
|
||||
}
|
||||
};
|
||||
@@ -365,21 +396,23 @@ function check_upgrade(version: string) {
|
||||
if (version) {
|
||||
const dev_version = version.split(',')[0];
|
||||
const stable_version = version.split(',')[1];
|
||||
|
||||
console.log(
|
||||
'latest dev version: ' +
|
||||
dev_version +
|
||||
', latest stable version: ' +
|
||||
stable_version
|
||||
);
|
||||
console.log(
|
||||
'Version upgrade check from version ' +
|
||||
THIS_VERSION +
|
||||
', upgradable: ' +
|
||||
VERSION_IS_UPGRADEABLE
|
||||
'Upgrade this version (' +
|
||||
THIS_VERSION +
|
||||
') to dev (' +
|
||||
dev_version +
|
||||
') is ' +
|
||||
(DEV_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO') +
|
||||
' and to stable (' +
|
||||
stable_version +
|
||||
') is ' +
|
||||
(STABLE_VERSION_IS_UPGRADEABLE ? 'YES' : 'NO')
|
||||
);
|
||||
data = {
|
||||
emsesp_version: THIS_VERSION,
|
||||
upgradeable: VERSION_IS_UPGRADEABLE
|
||||
dev_upgradeable: DEV_VERSION_IS_UPGRADEABLE,
|
||||
stable_upgradeable: STABLE_VERSION_IS_UPGRADEABLE
|
||||
};
|
||||
} else {
|
||||
console.log('requesting ems-esp version (' + THIS_VERSION + ')');
|
||||
@@ -410,8 +443,8 @@ let ntp_settings = {
|
||||
tz_label: 'Europe/Amsterdam',
|
||||
tz_format: 'CET-1CEST,M3.5.0,M10.5.0/3'
|
||||
};
|
||||
const ntp_status = {
|
||||
status: 2,
|
||||
let ntp_status = {
|
||||
status: 0, // 0 = disabled, 1 = inactive, 2 = active
|
||||
utc_time: '2021-04-01T14:25:42Z',
|
||||
local_time: '2021-04-01T16:25:42',
|
||||
server: 'time.google.com',
|
||||
@@ -560,14 +593,15 @@ let mqtt_settings = {
|
||||
publish_time_heartbeat: 60,
|
||||
publish_time_water: 60,
|
||||
mqtt_qos: 0,
|
||||
rootCA: '',
|
||||
mqtt_retain: false,
|
||||
ha_enabled: true,
|
||||
nested_format: 1,
|
||||
discovery_type: 0,
|
||||
discovery_prefix: 'homeassistant',
|
||||
send_response: true,
|
||||
publish_single: false
|
||||
publish_single: false,
|
||||
enableTLS: true,
|
||||
rootCA: ''
|
||||
};
|
||||
const mqtt_status = {
|
||||
enabled: true,
|
||||
@@ -953,19 +987,94 @@ const emsesp_coredata_custom = {
|
||||
const emsesp_sensordata = {
|
||||
// ts: [],
|
||||
ts: [
|
||||
{ id: '28-233D-9497-0C03', n: 'Dallas 1', t: 25.7, o: 1.2, u: 1 },
|
||||
{ id: '28-243D-7437-1E3A', n: 'Dallas 2 outside', t: 26.1, o: 0, u: 1 },
|
||||
{ id: '28-243E-7437-1E3B', n: 'Zolder', t: 27.1, o: 0, u: 1 },
|
||||
{ id: '28-183D-1892-0C33', n: 'Roof', o: 2, u: 1 } // no temperature
|
||||
{ id: '28-233D-9497-0C03', n: 'Dallas 1', t: 25.7, o: 1.2, u: 1, s: false },
|
||||
{
|
||||
id: '28-243D-7437-1E3A',
|
||||
n: 'Dallas 2 outside',
|
||||
t: 26.1,
|
||||
o: 0,
|
||||
u: 1,
|
||||
s: false
|
||||
},
|
||||
{ id: '28-243E-7437-1E3B', n: 'Zolder', t: 27.1, o: 0, u: 1, s: false },
|
||||
{ id: '28-183D-1892-0C33', n: 'Roof', o: 2, u: 1, s: false }, // no temperature
|
||||
{
|
||||
id: '28_1767_7B13_2502',
|
||||
n: 'gateway_temperature',
|
||||
t: 28.1,
|
||||
o: 0,
|
||||
u: 1,
|
||||
s: true
|
||||
} // internal system temp
|
||||
],
|
||||
// as: [],
|
||||
as: [
|
||||
{ id: 1, g: 36, n: 'motor', v: 0, u: 0, o: 17, f: 0, t: 0, d: false },
|
||||
{ id: 2, g: 37, n: 'External switch', v: 13, u: 0, o: 17, f: 0, t: 1, d: false },
|
||||
{ id: 3, g: 39, n: 'Pulse count', v: 144, u: 0, o: 0, f: 0, t: 2, d: false },
|
||||
{ id: 4, g: 40, n: 'Pressure', v: 16, u: 17, o: 0, f: 0, t: 3, d: false }
|
||||
{ id: 1, g: 35, n: 'motor', v: 0, u: 0, o: 17, f: 0, t: 7, d: false, s: false },
|
||||
{
|
||||
id: 2,
|
||||
g: 34,
|
||||
n: 'External_switch',
|
||||
v: 13,
|
||||
u: 0,
|
||||
o: 17,
|
||||
f: 0,
|
||||
t: 1,
|
||||
d: false,
|
||||
s: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
g: 37,
|
||||
n: 'Pulse_count',
|
||||
v: 144,
|
||||
u: 0,
|
||||
o: 0,
|
||||
f: 0,
|
||||
t: 2,
|
||||
d: false,
|
||||
s: false
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
g: 23,
|
||||
n: 'Pressure',
|
||||
v: 16,
|
||||
u: 17,
|
||||
o: 0,
|
||||
f: 0,
|
||||
t: 3,
|
||||
d: false,
|
||||
s: false
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
g: 39,
|
||||
n: 'core_voltage',
|
||||
v: 3.34,
|
||||
u: 23,
|
||||
o: 0,
|
||||
f: 0.003771,
|
||||
t: 3,
|
||||
d: false,
|
||||
s: true
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
g: 36,
|
||||
n: 'supply_voltage',
|
||||
v: 12.21,
|
||||
u: 23,
|
||||
o: 0,
|
||||
f: 0.017,
|
||||
t: 3,
|
||||
d: false,
|
||||
s: true
|
||||
}
|
||||
],
|
||||
analog_enabled: true
|
||||
analog_enabled: true,
|
||||
available_gpios: [] as number[],
|
||||
exclude_types: [] as number[],
|
||||
platform: 'ESP32'
|
||||
};
|
||||
|
||||
const activity = {
|
||||
@@ -4326,7 +4435,15 @@ router
|
||||
router
|
||||
.get(NTP_SETTINGS_ENDPOINT, () => ntp_settings)
|
||||
.get(NTP_STATUS_ENDPOINT, () => ntp_status)
|
||||
.post(TIME_ENDPOINT, () => status(200))
|
||||
.post(TIME_ENDPOINT, async (request: any) => {
|
||||
const rsp = await request.json();
|
||||
const local_time = rsp.local_time;
|
||||
ntp_status.status = 1;
|
||||
ntp_status.local_time = local_time;
|
||||
ntp_status.utc_time = local_time;
|
||||
console.log('ntp time set to', local_time);
|
||||
return status(200);
|
||||
})
|
||||
.post(NTP_SETTINGS_ENDPOINT, async (request: any) => {
|
||||
ntp_settings = await request.json();
|
||||
console.log('ntp settings saved', ntp_settings);
|
||||
@@ -4336,13 +4453,19 @@ router
|
||||
// SYSTEM and SETTINGS
|
||||
router
|
||||
.get(ACTIVITY_ENDPOINT, () => activity)
|
||||
.get(SYSTEM_STATUS_ENDPOINT, () => {
|
||||
.get(SYSTEM_STATUS_ENDPOINT, async () => {
|
||||
if (countHardwarePoll >= 2) {
|
||||
countHardwarePoll = 0;
|
||||
system_status.status = 0; // SYSTEM_STATUS_NORMAL
|
||||
}
|
||||
countHardwarePoll++;
|
||||
|
||||
// Add a small artificial delay to better simulate a real network, to see if flash is fixed
|
||||
// await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||
|
||||
system_status.uptime += 3; // simulate 3 seconds of uptime
|
||||
system_status.bus_uptime += 3;
|
||||
|
||||
return system_status;
|
||||
})
|
||||
.get(SECURITY_SETTINGS_ENDPOINT, () => security_settings)
|
||||
@@ -4359,97 +4482,55 @@ router
|
||||
// EMS-ESP Project stuff
|
||||
//
|
||||
|
||||
// Lookup maps to avoid repetitive branching per request
|
||||
const DEVICE_DATA_MAP: Record<number, any> = {
|
||||
1: emsesp_devicedata_1,
|
||||
2: emsesp_devicedata_2,
|
||||
3: emsesp_devicedata_3,
|
||||
4: emsesp_devicedata_4,
|
||||
5: emsesp_devicedata_5,
|
||||
6: emsesp_devicedata_6,
|
||||
7: emsesp_devicedata_7,
|
||||
8: emsesp_devicedata_8,
|
||||
9: emsesp_devicedata_9,
|
||||
10: emsesp_devicedata_10,
|
||||
11: emsesp_devicedata_11,
|
||||
99: emsesp_devicedata_99
|
||||
};
|
||||
|
||||
const DEVICE_ENTITIES_MAP: Record<number, any> = {
|
||||
1: emsesp_deviceentities_1,
|
||||
2: emsesp_deviceentities_2,
|
||||
3: emsesp_deviceentities_3,
|
||||
4: emsesp_deviceentities_4,
|
||||
5: emsesp_deviceentities_5,
|
||||
6: emsesp_deviceentities_6,
|
||||
7: emsesp_deviceentities_7,
|
||||
8: emsesp_deviceentities_8,
|
||||
9: emsesp_deviceentities_9,
|
||||
10: emsesp_deviceentities_10
|
||||
};
|
||||
|
||||
function deviceData(id: number) {
|
||||
if (id == 1) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_1), { headers });
|
||||
}
|
||||
if (id == 2) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_2), { headers });
|
||||
}
|
||||
if (id == 3) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_3), { headers });
|
||||
}
|
||||
if (id == 4) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_4), { headers });
|
||||
}
|
||||
if (id == 5) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_5), { headers });
|
||||
}
|
||||
if (id == 6) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_6), { headers });
|
||||
}
|
||||
if (id == 7) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_7), { headers });
|
||||
}
|
||||
if (id == 8) {
|
||||
if (id === 8) {
|
||||
// test changing the selected flow temp on a Bosch Compress 7000i AW Heat Pump (Boiler/HP)
|
||||
emsesp_devicedata_8.nodes[4].v = Math.floor(Math.random() * 100);
|
||||
return new Response(encoder.encode(emsesp_devicedata_8), { headers });
|
||||
}
|
||||
if (id == 9) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_9), { headers });
|
||||
}
|
||||
if (id == 10) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_10), { headers });
|
||||
}
|
||||
if (id == 11) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_11), { headers });
|
||||
}
|
||||
if (id == 99) {
|
||||
return new Response(encoder.encode(emsesp_devicedata_99), { headers });
|
||||
|
||||
const data = DEVICE_DATA_MAP[id];
|
||||
if (data) {
|
||||
return new Response(encoder.encode(data) as BodyInit, { headers });
|
||||
}
|
||||
}
|
||||
|
||||
function deviceEntities(id: number) {
|
||||
if (id == 1) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_1), { headers });
|
||||
}
|
||||
if (id == 2) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_2), { headers });
|
||||
}
|
||||
if (id == 3) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_3), { headers });
|
||||
}
|
||||
if (id == 4) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_4), { headers });
|
||||
}
|
||||
if (id == 5) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_5), { headers });
|
||||
}
|
||||
if (id == 6) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_6), { headers });
|
||||
}
|
||||
if (id == 7) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_7), { headers });
|
||||
}
|
||||
if (id == 8) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_8), { headers });
|
||||
}
|
||||
if (id == 9) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_9), { headers });
|
||||
}
|
||||
if (id == 10) {
|
||||
return new Response(encoder.encode(emsesp_deviceentities_10), { headers });
|
||||
}
|
||||
// not found, return empty
|
||||
return new Response(encoder.encode(emsesp_deviceentities_none), { headers });
|
||||
const data = DEVICE_ENTITIES_MAP[id] || emsesp_deviceentities_none;
|
||||
return new Response(encoder.encode(data) as BodyInit, { headers });
|
||||
}
|
||||
|
||||
// prepare dashboard data
|
||||
function getDashboardEntityData(id: number) {
|
||||
let device_data = {};
|
||||
if (id == 1) device_data = emsesp_devicedata_1;
|
||||
else if (id == 2) device_data = emsesp_devicedata_2;
|
||||
else if (id == 3) device_data = emsesp_devicedata_3;
|
||||
else if (id == 4) device_data = emsesp_devicedata_4;
|
||||
else if (id == 5) device_data = emsesp_devicedata_5;
|
||||
else if (id == 6) device_data = emsesp_devicedata_6;
|
||||
else if (id == 7) device_data = emsesp_devicedata_7;
|
||||
else if (id == 8) device_data = emsesp_devicedata_8;
|
||||
else if (id == 9) device_data = emsesp_devicedata_9;
|
||||
else if (id == 10) device_data = emsesp_devicedata_10;
|
||||
else if (id == 11) device_data = emsesp_devicedata_11;
|
||||
else if (id == 99) device_data = emsesp_devicedata_99;
|
||||
const device_data = DEVICE_DATA_MAP[id] || { nodes: [] };
|
||||
|
||||
// filter device_data on
|
||||
// - only add favorite (mask has bit 8 set) except for Custom Entities (type 99)
|
||||
@@ -4471,7 +4552,7 @@ router
|
||||
settings = await request.json();
|
||||
console.log('application settings saved', settings);
|
||||
return status(200); // no restart needed
|
||||
// return status(205); // restart needed
|
||||
// return status(205); // reboot required
|
||||
})
|
||||
|
||||
// Device Data
|
||||
@@ -4486,6 +4567,28 @@ router
|
||||
.get(EMSESP_SENSOR_DATA_ENDPOINT, () => {
|
||||
// random change the zolder temperature 0-100
|
||||
emsesp_sensordata.ts[2].t = Math.floor(Math.random() * 100);
|
||||
|
||||
// Build list of available GPIOs (S3 board pins) excluding used ones
|
||||
// and sort it
|
||||
const allGPIOs = [
|
||||
2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 21, 33, 34, 35, 36, 37, 38,
|
||||
45, 46
|
||||
];
|
||||
const usedGPIOs = new Set([
|
||||
settings.led_gpio,
|
||||
settings.dallas_gpio,
|
||||
settings.pbutton_gpio,
|
||||
settings.rx_gpio,
|
||||
settings.tx_gpio,
|
||||
...emsesp_sensordata.as.map((item) => item.g)
|
||||
]);
|
||||
|
||||
emsesp_sensordata.available_gpios = allGPIOs
|
||||
.filter((gpio) => !usedGPIOs.has(gpio))
|
||||
.sort((a, b) => a - b);
|
||||
|
||||
// console.log('available_gpios', emsesp_sensordata.available_gpios);
|
||||
|
||||
return emsesp_sensordata;
|
||||
})
|
||||
.get(EMSESP_DEVICEDATA_ENDPOINT1, (request) =>
|
||||
@@ -4507,8 +4610,7 @@ router
|
||||
{};
|
||||
|
||||
let fake = false;
|
||||
|
||||
// fake = true; // for testing, shows a subset of data
|
||||
// let fake = true; // toggle for testing, shows a subset of data
|
||||
|
||||
if (!fake) {
|
||||
// pick EMS devices from coredata
|
||||
@@ -4539,80 +4641,80 @@ router
|
||||
}
|
||||
|
||||
// add temperature sensor data. no command c
|
||||
let sensor_data: any[] = [];
|
||||
sensor_data = emsesp_sensordata.ts.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.TEMPERATURESENSOR_UID * 100 + index,
|
||||
dv: {
|
||||
id: '00' + item.n,
|
||||
v: item.t, // value is called t in ts (temperature)
|
||||
u: item.u
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.TEMPERATURESENSOR_UID,
|
||||
t: DeviceType.TEMPERATURESENSOR,
|
||||
nodes: sensor_data
|
||||
};
|
||||
// only add to dashboard if we have values
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
// remove system sensors first
|
||||
const enabledTemperatureSensors = emsesp_sensordata.ts.filter(
|
||||
(item) => !item.s
|
||||
);
|
||||
if (enabledTemperatureSensors.length > 0) {
|
||||
const sensor_data = enabledTemperatureSensors.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.TEMPERATURESENSOR_UID * 100 + index,
|
||||
dv: {
|
||||
id: '00' + item.n,
|
||||
v: item.t, // value is called t in ts (temperature)
|
||||
u: item.u
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.TEMPERATURESENSOR_UID,
|
||||
t: DeviceType.TEMPERATURESENSOR,
|
||||
nodes: sensor_data
|
||||
};
|
||||
dashboard_nodes.push(dashboard_object);
|
||||
}
|
||||
|
||||
// add analog sensor data. no command c
|
||||
// remove disabled sensors first (t = 0)
|
||||
sensor_data = emsesp_sensordata.as.filter((item) => item.t !== 0);
|
||||
sensor_data = sensor_data.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.ANALOGSENSOR_UID * 100 + index,
|
||||
dv: {
|
||||
id: '00' + item.n,
|
||||
v: item.v,
|
||||
u: item.u
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.ANALOGSENSOR_UID,
|
||||
t: DeviceType.ANALOGSENSOR,
|
||||
nodes: sensor_data
|
||||
};
|
||||
// only add to dashboard if we have values
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
// remove disabled and system sensors first (t = 0) and create data in one pass
|
||||
const enabledAnalogSensors = emsesp_sensordata.as.filter(
|
||||
(item) => item.t !== 0 && !item.s
|
||||
);
|
||||
if (enabledAnalogSensors.length > 0) {
|
||||
const sensor_data = enabledAnalogSensors.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.ANALOGSENSOR_UID * 100 + index,
|
||||
dv: {
|
||||
id: '00' + item.n,
|
||||
v: item.v,
|
||||
u: item.u
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.ANALOGSENSOR_UID,
|
||||
t: DeviceType.ANALOGSENSOR,
|
||||
nodes: sensor_data
|
||||
};
|
||||
dashboard_nodes.push(dashboard_object);
|
||||
}
|
||||
|
||||
// add the scheduler data
|
||||
// filter emsesp_schedule with only if it has a name
|
||||
let scheduler_data = emsesp_schedule.schedule.filter((item) => item.name);
|
||||
let scheduler_data2 = scheduler_data.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.SCHEDULER_UID * 100 + index,
|
||||
dv: {
|
||||
id: '00' + item.name,
|
||||
v: item.active ? 'on' : 'off',
|
||||
c: item.name,
|
||||
l: ['off', 'on']
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.SCHEDULER_UID,
|
||||
t: DeviceType.SCHEDULER,
|
||||
nodes: scheduler_data2
|
||||
};
|
||||
// only add to dashboard if we have values
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
// filter emsesp_schedule with only if it has a name and create data in one pass
|
||||
const namedSchedules = emsesp_schedule.schedule.filter((item) => item.name);
|
||||
if (namedSchedules.length > 0) {
|
||||
const scheduler_data = namedSchedules.map((item, index) => ({
|
||||
id: DeviceTypeUniqueID.SCHEDULER_UID * 100 + index,
|
||||
dv: {
|
||||
id: '00' + item.name,
|
||||
v: item.active ? 'on' : 'off',
|
||||
c: item.name,
|
||||
l: ['off', 'on']
|
||||
}
|
||||
}));
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.SCHEDULER_UID,
|
||||
t: DeviceType.SCHEDULER,
|
||||
nodes: scheduler_data
|
||||
};
|
||||
dashboard_nodes.push(dashboard_object);
|
||||
}
|
||||
} else {
|
||||
// for testing only
|
||||
|
||||
// add the custom entity data
|
||||
dashboard_object = {
|
||||
id: DeviceTypeUniqueID.CUSTOM_UID, // unique ID for custom entities
|
||||
t: DeviceType.CUSTOM,
|
||||
nodes: getDashboardEntityData(DeviceTypeUniqueID.CUSTOM_UID)
|
||||
};
|
||||
if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
dashboard_nodes.push(dashboard_object);
|
||||
}
|
||||
|
||||
// dashboard_object = {
|
||||
// id: DeviceTypeUniqueID.CUSTOM_UID, // unique ID for custom entities
|
||||
// t: DeviceType.CUSTOM,
|
||||
// nodes: getDashboardEntityData(DeviceTypeUniqueID.CUSTOM_UID)
|
||||
// };
|
||||
// if ((dashboard_object.nodes ?? []).length > 0) {
|
||||
// dashboard_nodes.push(dashboard_object);
|
||||
// }
|
||||
// add the scheduler data
|
||||
// let scheduler_data = emsesp_schedule.schedule.filter((item) => item.name);
|
||||
// let scheduler_data2 = scheduler_data.map((item, index) => ({
|
||||
@@ -4641,8 +4743,12 @@ router
|
||||
};
|
||||
// console.log('dashboardData: ', dashboardData);
|
||||
|
||||
// Clear references to help with garbage collection
|
||||
dashboard_nodes = [];
|
||||
dashboard_object = {};
|
||||
|
||||
// return dashboard_data; // if not using msgpack
|
||||
return new Response(encoder.encode(dashboardData), { headers }); // msgpack it
|
||||
return new Response(encoder.encode(dashboardData) as BodyInit, { headers }); // msgpack it
|
||||
})
|
||||
|
||||
// Customizations
|
||||
@@ -4811,6 +4917,7 @@ router
|
||||
if (objIndex !== -1) {
|
||||
emsesp_sensordata.ts[objIndex].n = ts.name;
|
||||
emsesp_sensordata.ts[objIndex].o = ts.offset;
|
||||
emsesp_sensordata.ts[objIndex].s = ts.is_system;
|
||||
}
|
||||
console.log('temp sensor saved', ts);
|
||||
return status(200);
|
||||
@@ -4828,21 +4935,25 @@ router
|
||||
u: as.uom,
|
||||
t: as.type,
|
||||
d: as.deleted,
|
||||
s: as.is_system,
|
||||
v: 0 // must be added for demo only
|
||||
});
|
||||
} else {
|
||||
if (as.deleted) {
|
||||
emsesp_sensordata.as[objIndex].d = true;
|
||||
var filtered = emsesp_sensordata.as.filter(function (value, index, arr) {
|
||||
return !value.d;
|
||||
});
|
||||
emsesp_sensordata.as = filtered;
|
||||
// Remove deleted items in-place to avoid creating new arrays
|
||||
for (let i = emsesp_sensordata.as.length - 1; i >= 0; i--) {
|
||||
if (emsesp_sensordata.as[i].d) {
|
||||
emsesp_sensordata.as.splice(i, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
emsesp_sensordata.as[objIndex].n = as.name;
|
||||
emsesp_sensordata.as[objIndex].f = as.factor;
|
||||
emsesp_sensordata.as[objIndex].o = as.offset;
|
||||
emsesp_sensordata.as[objIndex].u = as.uom;
|
||||
emsesp_sensordata.as[objIndex].t = as.type;
|
||||
emsesp_sensordata.as[objIndex].s = as.is_system;
|
||||
}
|
||||
}
|
||||
console.log('analog sensor saved', as);
|
||||
@@ -4864,7 +4975,8 @@ router
|
||||
phy_type: settings.phy_type,
|
||||
eth_power: settings.eth_power,
|
||||
eth_phy_addr: settings.eth_phy_addr,
|
||||
eth_clock_mode: settings.eth_clock_mode
|
||||
eth_clock_mode: settings.eth_clock_mode,
|
||||
led_type: settings.led_type
|
||||
};
|
||||
|
||||
if (board_profile == 'S32') {
|
||||
@@ -4878,6 +4990,19 @@ router
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'S32S3') {
|
||||
// BBQKees Gateway S3
|
||||
data.led_gpio = 2;
|
||||
data.dallas_gpio = 18;
|
||||
data.rx_gpio = 5;
|
||||
data.tx_gpio = 17;
|
||||
data.pbutton_gpio = 0;
|
||||
data.phy_type = 0;
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'E32') {
|
||||
// BBQKees Gateway E32
|
||||
data.led_gpio = 2;
|
||||
@@ -4889,6 +5014,19 @@ router
|
||||
data.eth_power = 16;
|
||||
data.eth_phy_addr = 1;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'E32V2') {
|
||||
// BBQKees Gateway E32 V2
|
||||
data.led_gpio = 2;
|
||||
data.dallas_gpio = 14;
|
||||
data.rx_gpio = 4;
|
||||
data.tx_gpio = 5;
|
||||
data.pbutton_gpio = 34;
|
||||
data.phy_type = 1;
|
||||
data.eth_power = 15;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 1;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'MH-ET') {
|
||||
// MH-ET Live D1 Mini
|
||||
data.led_gpio = 2;
|
||||
@@ -4900,6 +5038,7 @@ router
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'NODEMCU') {
|
||||
// NodeMCU 32S
|
||||
data.led_gpio = 2;
|
||||
@@ -4911,6 +5050,7 @@ router
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'LOLIN') {
|
||||
// Lolin D32
|
||||
data.led_gpio = 2;
|
||||
@@ -4922,6 +5062,7 @@ router
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'OLIMEX') {
|
||||
// Olimex ESP32-EVB (uses U1TXD/U1RXD/BUTTON, no LED or Dallas)
|
||||
data.led_gpio = 0;
|
||||
@@ -4933,6 +5074,7 @@ router
|
||||
data.eth_power = -1;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'OLIMEXPOE') {
|
||||
// Olimex ESP32-POE
|
||||
data.led_gpio = 0;
|
||||
@@ -4944,6 +5086,7 @@ router
|
||||
data.eth_power = 12;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 3;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'C3MINI') {
|
||||
// Lolin C3 mini
|
||||
data.led_gpio = 7;
|
||||
@@ -4955,6 +5098,7 @@ router
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'S2MINI') {
|
||||
// Lolin C3 mini
|
||||
data.led_gpio = 15;
|
||||
@@ -4966,6 +5110,7 @@ router
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
} else if (board_profile == 'S3MINI') {
|
||||
// Liligo S3 mini
|
||||
data.led_gpio = 17;
|
||||
@@ -4977,6 +5122,7 @@ router
|
||||
data.eth_power = 0;
|
||||
data.eth_phy_addr = 0;
|
||||
data.eth_clock_mode = 0;
|
||||
data.led_type = 0;
|
||||
}
|
||||
|
||||
data.board_profile =
|
||||
@@ -5009,6 +5155,14 @@ router
|
||||
// upload URL
|
||||
console.log('upload File from URL', content.param);
|
||||
return status(200);
|
||||
} else if (action === 'resetMQTT') {
|
||||
// reset MQTT
|
||||
console.log('resetting MQTT...');
|
||||
return status(200);
|
||||
} else if (action === 'setPartition') {
|
||||
// set partition
|
||||
console.log('setting partition to', content.param);
|
||||
return status(200);
|
||||
}
|
||||
}
|
||||
return status(404); // cmd not found
|
||||
@@ -1,308 +0,0 @@
|
||||
# This file is generated by running "yarn install" inside your project.
|
||||
# Manual changes might be lost - proceed with caution!
|
||||
|
||||
__metadata:
|
||||
version: 8
|
||||
cacheKey: 10c0
|
||||
|
||||
"@babel/code-frame@npm:^7.26.2":
|
||||
version: 7.26.2
|
||||
resolution: "@babel/code-frame@npm:7.26.2"
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier": "npm:^7.25.9"
|
||||
js-tokens: "npm:^4.0.0"
|
||||
picocolors: "npm:^1.0.0"
|
||||
checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/generator@npm:^7.26.10, @babel/generator@npm:^7.26.5":
|
||||
version: 7.26.10
|
||||
resolution: "@babel/generator@npm:7.26.10"
|
||||
dependencies:
|
||||
"@babel/parser": "npm:^7.26.10"
|
||||
"@babel/types": "npm:^7.26.10"
|
||||
"@jridgewell/gen-mapping": "npm:^0.3.5"
|
||||
"@jridgewell/trace-mapping": "npm:^0.3.25"
|
||||
jsesc: "npm:^3.0.2"
|
||||
checksum: 10c0/88b3b3ea80592fc89349c4e1a145e1386e4042866d2507298adf452bf972f68d13bf699a845e6ab8c028bd52c2247013eb1221b86e1db5c9779faacba9c4b10e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-string-parser@npm:^7.25.9":
|
||||
version: 7.25.9
|
||||
resolution: "@babel/helper-string-parser@npm:7.25.9"
|
||||
checksum: 10c0/7244b45d8e65f6b4338a6a68a8556f2cb161b782343e97281a5f2b9b93e420cad0d9f5773a59d79f61d0c448913d06f6a2358a87f2e203cf112e3c5b53522ee6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-validator-identifier@npm:^7.25.9":
|
||||
version: 7.25.9
|
||||
resolution: "@babel/helper-validator-identifier@npm:7.25.9"
|
||||
checksum: 10c0/4fc6f830177b7b7e887ad3277ddb3b91d81e6c4a24151540d9d1023e8dc6b1c0505f0f0628ae653601eb4388a8db45c1c14b2c07a9173837aef7e4116456259d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/parser@npm:^7.26.10, @babel/parser@npm:^7.26.7, @babel/parser@npm:^7.26.9":
|
||||
version: 7.26.10
|
||||
resolution: "@babel/parser@npm:7.26.10"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.26.10"
|
||||
bin:
|
||||
parser: ./bin/babel-parser.js
|
||||
checksum: 10c0/c47f5c0f63cd12a663e9dc94a635f9efbb5059d98086a92286d7764357c66bceba18ccbe79333e01e9be3bfb8caba34b3aaebfd8e62c3d5921c8cf907267be75
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/template@npm:^7.26.9":
|
||||
version: 7.26.9
|
||||
resolution: "@babel/template@npm:7.26.9"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.26.2"
|
||||
"@babel/parser": "npm:^7.26.9"
|
||||
"@babel/types": "npm:^7.26.9"
|
||||
checksum: 10c0/019b1c4129cc01ad63e17529089c2c559c74709d225f595eee017af227fee11ae8a97a6ab19ae6768b8aa22d8d75dcb60a00b28f52e9fa78140672d928bc1ae9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/traverse@npm:^7.26.7":
|
||||
version: 7.26.10
|
||||
resolution: "@babel/traverse@npm:7.26.10"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.26.2"
|
||||
"@babel/generator": "npm:^7.26.10"
|
||||
"@babel/parser": "npm:^7.26.10"
|
||||
"@babel/template": "npm:^7.26.9"
|
||||
"@babel/types": "npm:^7.26.10"
|
||||
debug: "npm:^4.3.1"
|
||||
globals: "npm:^11.1.0"
|
||||
checksum: 10c0/4e86bb4e3c30a6162bb91df86329df79d96566c3e2d9ccba04f108c30473a3a4fd360d9990531493d90f6a12004f10f616bf9b9229ca30c816b708615e9de2ac
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/types@npm:^7.26.10, @babel/types@npm:^7.26.7, @babel/types@npm:^7.26.9":
|
||||
version: 7.26.10
|
||||
resolution: "@babel/types@npm:7.26.10"
|
||||
dependencies:
|
||||
"@babel/helper-string-parser": "npm:^7.25.9"
|
||||
"@babel/helper-validator-identifier": "npm:^7.25.9"
|
||||
checksum: 10c0/7a7f83f568bfc3dfabfaf9ae3a97ab5c061726c0afa7dcd94226d4f84a81559da368ed79671e3a8039d16f12476cf110381a377ebdea07587925f69628200dac
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jridgewell/gen-mapping@npm:^0.3.5":
|
||||
version: 0.3.8
|
||||
resolution: "@jridgewell/gen-mapping@npm:0.3.8"
|
||||
dependencies:
|
||||
"@jridgewell/set-array": "npm:^1.2.1"
|
||||
"@jridgewell/sourcemap-codec": "npm:^1.4.10"
|
||||
"@jridgewell/trace-mapping": "npm:^0.3.24"
|
||||
checksum: 10c0/c668feaf86c501d7c804904a61c23c67447b2137b813b9ce03eca82cb9d65ac7006d766c218685d76e3d72828279b6ee26c347aa1119dab23fbaf36aed51585a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jridgewell/resolve-uri@npm:^3.1.0":
|
||||
version: 3.1.2
|
||||
resolution: "@jridgewell/resolve-uri@npm:3.1.2"
|
||||
checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jridgewell/set-array@npm:^1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "@jridgewell/set-array@npm:1.2.1"
|
||||
checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14":
|
||||
version: 1.5.0
|
||||
resolution: "@jridgewell/sourcemap-codec@npm:1.5.0"
|
||||
checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25":
|
||||
version: 0.3.25
|
||||
resolution: "@jridgewell/trace-mapping@npm:0.3.25"
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri": "npm:^3.1.0"
|
||||
"@jridgewell/sourcemap-codec": "npm:^1.4.14"
|
||||
checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@msgpack/msgpack@npm:^3.1.1":
|
||||
version: 3.1.1
|
||||
resolution: "@msgpack/msgpack@npm:3.1.1"
|
||||
checksum: 10c0/f7048d2145ee39e4979b4e6bb9d9723db031ea7b4f00d0ec96258fbff40b8af027783f391ee294e5385a5a91849a77d934ad08eb11d08253484eee8f8f0866ff
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@trivago/prettier-plugin-sort-imports@npm:^5.2.2":
|
||||
version: 5.2.2
|
||||
resolution: "@trivago/prettier-plugin-sort-imports@npm:5.2.2"
|
||||
dependencies:
|
||||
"@babel/generator": "npm:^7.26.5"
|
||||
"@babel/parser": "npm:^7.26.7"
|
||||
"@babel/traverse": "npm:^7.26.7"
|
||||
"@babel/types": "npm:^7.26.7"
|
||||
javascript-natural-sort: "npm:^0.7.1"
|
||||
lodash: "npm:^4.17.21"
|
||||
peerDependencies:
|
||||
"@vue/compiler-sfc": 3.x
|
||||
prettier: 2.x - 3.x
|
||||
prettier-plugin-svelte: 3.x
|
||||
svelte: 4.x || 5.x
|
||||
peerDependenciesMeta:
|
||||
"@vue/compiler-sfc":
|
||||
optional: true
|
||||
prettier-plugin-svelte:
|
||||
optional: true
|
||||
svelte:
|
||||
optional: true
|
||||
checksum: 10c0/2a4f0464f1f5a294bcd34558fb053f8263f0c62c4a7fcdd3ce40c9822a68ac8b4d951700ab6d01eb3919efe0ed44e4191997edd494d59679b22db1c0db00474e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"asap@npm:^2.0.0":
|
||||
version: 2.0.6
|
||||
resolution: "asap@npm:2.0.6"
|
||||
checksum: 10c0/c6d5e39fe1f15e4b87677460bd66b66050cd14c772269cee6688824c1410a08ab20254bb6784f9afb75af9144a9f9a7692d49547f4d19d715aeb7c0318f3136d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"debug@npm:^4.3.1":
|
||||
version: 4.4.0
|
||||
resolution: "debug@npm:4.4.0"
|
||||
dependencies:
|
||||
ms: "npm:^2.1.3"
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
checksum: 10c0/db94f1a182bf886f57b4755f85b3a74c39b5114b9377b7ab375dc2cfa3454f09490cc6c30f829df3fc8042bc8b8995f6567ce5cd96f3bc3688bd24027197d9de
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dezalgo@npm:^1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "dezalgo@npm:1.0.4"
|
||||
dependencies:
|
||||
asap: "npm:^2.0.0"
|
||||
wrappy: "npm:1"
|
||||
checksum: 10c0/8a870ed42eade9a397e6141fe5c025148a59ed52f1f28b1db5de216b4d57f0af7a257070c3af7ce3d5508c1ce9dd5009028a76f4b2cc9370dc56551d2355fad8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"formidable@npm:^3.5.2":
|
||||
version: 3.5.2
|
||||
resolution: "formidable@npm:3.5.2"
|
||||
dependencies:
|
||||
dezalgo: "npm:^1.0.4"
|
||||
hexoid: "npm:^2.0.0"
|
||||
once: "npm:^1.4.0"
|
||||
checksum: 10c0/c26d89ba84d392f0e68ba1aca9f779e0f2e94db053d95df562c730782956f302e3f069c07ab96f991415af915ac7b8771f4c813d298df43577fdf439e1e8741e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"globals@npm:^11.1.0":
|
||||
version: 11.12.0
|
||||
resolution: "globals@npm:11.12.0"
|
||||
checksum: 10c0/758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hexoid@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "hexoid@npm:2.0.0"
|
||||
checksum: 10c0/a9d5e6f4adeaefcb4a53803dd48bf0a242d92e8ec699555aea616c4bf8f91788f03093595085976f63d6830815dd080c063503540fabc7e854ebfb11161687c6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"itty-router@npm:^5.0.18":
|
||||
version: 5.0.18
|
||||
resolution: "itty-router@npm:5.0.18"
|
||||
checksum: 10c0/f21afcf16135622de665b340e16262add2c35dab037c051448df8a2dd49bd83dfa1cf9323000839994157202befaa79f95bbc9e0ed106114cb9da66275ad9408
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"javascript-natural-sort@npm:^0.7.1":
|
||||
version: 0.7.1
|
||||
resolution: "javascript-natural-sort@npm:0.7.1"
|
||||
checksum: 10c0/340f8ffc5d30fb516e06dc540e8fa9e0b93c865cf49d791fed3eac3bdc5fc71f0066fc81d44ec1433edc87caecaf9f13eec4a1fce8c5beafc709a71eaedae6fe
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"js-tokens@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "js-tokens@npm:4.0.0"
|
||||
checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jsesc@npm:^3.0.2":
|
||||
version: 3.1.0
|
||||
resolution: "jsesc@npm:3.1.0"
|
||||
bin:
|
||||
jsesc: bin/jsesc
|
||||
checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash@npm:^4.17.21":
|
||||
version: 4.17.21
|
||||
resolution: "lodash@npm:4.17.21"
|
||||
checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mock-api@workspace:.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "mock-api@workspace:."
|
||||
dependencies:
|
||||
"@msgpack/msgpack": "npm:^3.1.1"
|
||||
"@trivago/prettier-plugin-sort-imports": "npm:^5.2.2"
|
||||
formidable: "npm:^3.5.2"
|
||||
itty-router: "npm:^5.0.18"
|
||||
prettier: "npm:^3.5.3"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"ms@npm:^2.1.3":
|
||||
version: 2.1.3
|
||||
resolution: "ms@npm:2.1.3"
|
||||
checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"once@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "once@npm:1.4.0"
|
||||
dependencies:
|
||||
wrappy: "npm:1"
|
||||
checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"picocolors@npm:^1.0.0":
|
||||
version: 1.1.1
|
||||
resolution: "picocolors@npm:1.1.1"
|
||||
checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prettier@npm:^3.5.3":
|
||||
version: 3.5.3
|
||||
resolution: "prettier@npm:3.5.3"
|
||||
bin:
|
||||
prettier: bin/prettier.cjs
|
||||
checksum: 10c0/3880cb90b9dc0635819ab52ff571518c35bd7f15a6e80a2054c05dbc8a3aa6e74f135519e91197de63705bcb38388ded7e7230e2178432a1468005406238b877
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wrappy@npm:1":
|
||||
version: 1.0.2
|
||||
resolution: "wrappy@npm:1.0.2"
|
||||
checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
Reference in New Issue
Block a user