-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
5,345 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
{ | ||
'name': 'Release', | ||
'on': { 'release': { 'types': ['published'] } }, | ||
'jobs': | ||
{ | ||
'publish-release': | ||
{ | ||
'runs-on': 'ubuntu-latest', | ||
'strategy': { 'matrix': { 'node-version': ['16.x'] } }, | ||
'steps': | ||
[ | ||
{ 'uses': 'actions/checkout@v2' }, | ||
{ | ||
'name': 'Use Node.js ${{ matrix.node-version }}', | ||
'uses': 'actions/setup-node@v1', | ||
'with': { 'node-version': '${{ matrix.node-version }}' }, | ||
}, | ||
{ 'name': 'Install', 'run': 'npm ci' }, | ||
{ | ||
'name': 'Build', | ||
'run': 'npm run build', | ||
}, | ||
|
||
{ | ||
'name': 'Upload win x64', | ||
'uses': 'actions/upload-release-asset@v1.0.2', | ||
'env': { 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' }, | ||
'with': | ||
{ | ||
'upload_url': '${{ github.event.release.upload_url }}', | ||
'asset_path': './build/valetudo-helper-miioota.exe', | ||
'asset_name': 'valetudo-helper-miioota.exe', | ||
'asset_content_type': 'binary/octet-stream', | ||
}, | ||
}, | ||
{ | ||
'name': 'Upload lin x64', | ||
'uses': 'actions/upload-release-asset@v1.0.2', | ||
'env': { 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' }, | ||
'with': | ||
{ | ||
'upload_url': '${{ github.event.release.upload_url }}', | ||
'asset_path': './build/valetudo-helper-miioota-amd64', | ||
'asset_name': 'valetudo-helper-miioota-amd64', | ||
'asset_content_type': 'binary/octet-stream', | ||
}, | ||
}, | ||
{ | ||
'name': 'Upload lin armv7', | ||
'uses': 'actions/upload-release-asset@v1.0.2', | ||
'env': { 'GITHUB_TOKEN': '${{ secrets.GITHUB_TOKEN }}' }, | ||
'with': | ||
{ | ||
'upload_url': '${{ github.event.release.upload_url }}', | ||
'asset_path': './build/valetudo-helper-miioota-armv7', | ||
'asset_name': 'valetudo-helper-miioota-armv7', | ||
'asset_content_type': 'binary/octet-stream', | ||
}, | ||
}, | ||
], | ||
}, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/build_dependencies/ | ||
/build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
const EventEmitter = require("events").EventEmitter; | ||
const fs = require("fs"); | ||
const os = require("os"); | ||
const Tools = require("./utils/Tools"); | ||
const util = require("util"); | ||
|
||
class Logger { | ||
constructor() { | ||
this._logEventEmitter = new EventEmitter(); | ||
this._logFileMaxSizeCheckLineCounter = 1; | ||
|
||
|
||
this.logFileMaxSize = 4 * 1024 * 1024; //4MiB | ||
this.logLevel = Logger.LogLevels["info"]; | ||
|
||
this.logFilePath = os.type() === "Windows_NT" ? Logger.DEFAULT_LOGFILE_PATHS.WINNT : Logger.DEFAULT_LOGFILE_PATHS.POSIX; | ||
this.logFileWriteStream = fs.createWriteStream(this.logFilePath, Logger.LogFileOptions); | ||
} | ||
|
||
/** | ||
* @public | ||
* @return {string} | ||
*/ | ||
getLogLevel() { | ||
return Object.keys(Logger.LogLevels).find(key => { | ||
return Logger.LogLevels[key] === this.logLevel; | ||
}); | ||
} | ||
|
||
/** | ||
* @public | ||
* @param {string} value | ||
*/ | ||
setLogLevel(value) { | ||
if (Logger.LogLevels[value] === undefined) { | ||
throw new Error(`Invalid log level '${value}', valid are '${Object.keys(Logger.LogLevels).join("','")}'`); | ||
} else { | ||
this.logLevel = Logger.LogLevels[value]; | ||
} | ||
} | ||
|
||
/** | ||
* @public | ||
* @return {string} | ||
*/ | ||
getLogFilePath() { | ||
return this.logFilePath; | ||
} | ||
|
||
/** | ||
* @public | ||
* @param {string} filePath | ||
*/ | ||
setLogFilePath(filePath) { | ||
if (Tools.ARE_SAME_FILES(this.logFilePath, filePath)) { | ||
// We are already writing to that file | ||
return; | ||
} | ||
|
||
if (this.logFileWriteStream) { | ||
this.logFileWriteStream.close(); | ||
this.logFileWriteStream = null; | ||
} | ||
|
||
this.logFilePath = filePath; | ||
// Check if output is already redirected to that same file. If | ||
// it is, we do not need to write to that same file, because that | ||
// would lead to duplicate log entries. | ||
// Setting the LogFilename anyway ensures that the UI Log still works. | ||
if (!Tools.ARE_SAME_FILES(filePath, "/proc/self/fd/1")) { | ||
this.logFileWriteStream = fs.createWriteStream(this.logFilePath, Logger.LogFileOptions); | ||
} | ||
|
||
this.log("info", "Set Logfile to " + filePath); | ||
} | ||
|
||
|
||
/** | ||
* @private | ||
* @param {string} logLevel | ||
* @return {string} | ||
*/ | ||
buildLogLinePrefix(logLevel) { | ||
return `[${new Date().toISOString()}] [${logLevel}]`; | ||
} | ||
|
||
/** | ||
* @param {string} level | ||
* @param {...any} args | ||
* @private | ||
*/ | ||
log(level, ...args) { | ||
if (this.logLevel["level"] <= Logger.LogLevels[level]["level"]) { | ||
const logLinePrefix = this.buildLogLinePrefix(level.toUpperCase()); | ||
const logLine = [logLinePrefix, ...args].map(arg => { | ||
if (typeof arg === "string") { | ||
return arg; | ||
} | ||
|
||
return util.inspect( | ||
arg, | ||
{ | ||
depth: Infinity | ||
} | ||
); | ||
}).join(" "); | ||
|
||
Logger.LogLevels[level]["callback"](logLine); | ||
this.logLineToFile(logLine); | ||
this._logEventEmitter.emit("LogMessage", logLine); | ||
} | ||
} | ||
|
||
/** | ||
* @private | ||
* @param {string} line | ||
*/ | ||
logLineToFile(line) { | ||
if (this.logFileWriteStream) { | ||
/* | ||
As the default limit is rather large, we can avoid checking the logfile size on every single | ||
log line without running into any OOM issues | ||
*/ | ||
this._logFileMaxSizeCheckLineCounter = (this._logFileMaxSizeCheckLineCounter + 1) % 100; | ||
|
||
if (this._logFileMaxSizeCheckLineCounter === 0) { | ||
if ( | ||
this.logFilePath !== Logger.DEFAULT_LOGFILE_PATHS.WINNT && | ||
this.logFilePath !== Logger.DEFAULT_LOGFILE_PATHS.POSIX | ||
) { | ||
let fileSize = 0; | ||
|
||
try { | ||
const stat = fs.statSync(this.logFilePath); | ||
|
||
fileSize = stat.size; | ||
} catch (e) { | ||
this.error("Error while checking Logfile size:", e); | ||
} | ||
|
||
if (fileSize > this.logFileMaxSize) { | ||
this.logFileWriteStream.close(); | ||
fs.writeFileSync(this.logFilePath, ""); | ||
this.logFileWriteStream = fs.createWriteStream(this.logFilePath, Logger.LogFileOptions); | ||
|
||
this.warn(`Logfile ${this.logFilePath} was cleared after reaching a size of ${fileSize} bytes.`); | ||
} | ||
} | ||
} | ||
|
||
|
||
this.logFileWriteStream.write(line); | ||
this.logFileWriteStream.write("\n"); | ||
} | ||
} | ||
|
||
/** | ||
* @public | ||
* @param {any} listener | ||
*/ | ||
onLogMessage(listener) { | ||
this._logEventEmitter.on("LogMessage", listener); | ||
} | ||
|
||
/** | ||
* @public | ||
* @see console.trace | ||
* @param {...any} args | ||
*/ | ||
trace(...args) { | ||
this.log("trace", ...args); | ||
} | ||
|
||
/** | ||
* @public | ||
* @see console.debug | ||
* @param {...any} args | ||
*/ | ||
debug(...args) { | ||
this.log("debug", ...args); | ||
} | ||
|
||
/** | ||
* @public | ||
* @see console.info | ||
* @param {...any} args | ||
*/ | ||
info(...args) { | ||
this.log("info", ...args); | ||
} | ||
|
||
/** | ||
* @public | ||
* @see console.warn | ||
* @param {...any} args | ||
*/ | ||
warn(...args) { | ||
this.log("warn", ...args); | ||
} | ||
|
||
/** | ||
* @public | ||
* @see console.error | ||
* @param {...any} args | ||
*/ | ||
error( ...args) { | ||
this.log("error", ...args); | ||
} | ||
|
||
/** | ||
* @public | ||
*/ | ||
getProperties() { | ||
return { | ||
EVENTS: Logger.EVENTS, | ||
LogLevels: Logger.LogLevels | ||
}; | ||
} | ||
} | ||
|
||
Logger.EVENTS = { | ||
LogMessage: "LogMessage", | ||
}; | ||
|
||
Logger.LogLevels = Object.freeze({ | ||
// eslint-disable-next-line no-console | ||
"trace": {"level": -2, "callback": console.debug}, | ||
// eslint-disable-next-line no-console | ||
"debug": {"level": -1, "callback": console.debug}, | ||
// eslint-disable-next-line no-console | ||
"info": {"level": 0, "callback": console.info}, | ||
// eslint-disable-next-line no-console | ||
"warn": {"level": 1, "callback": console.warn}, | ||
// eslint-disable-next-line no-console | ||
"error": {"level": 2, "callback": console.error}, | ||
}); | ||
|
||
Logger.LogFileOptions = Object.freeze({ | ||
flags: "as" | ||
}); | ||
|
||
Logger.DEFAULT_LOGFILE_PATHS = Object.freeze({ | ||
POSIX: "/dev/null", | ||
WINNT: "\\\\.\\NUL" | ||
}); | ||
|
||
|
||
module.exports = new Logger(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# valetudo-helper-miioota | ||
|
||
![example](https://user-images.githubusercontent.com/974410/162240051-e27cb05b-0fda-4ce0-a6b6-4809a5935f63.png) | ||
|
||
|
||
valetudo-helper-miioota is a small utility that can be used to install rooted firmwares onto some older robots. | ||
|
||
Those being: | ||
- Roborock S5 (non Max!!) | ||
- Roborock V1 also known as the Xiaomi Mi Robot Vacuum (made before 2020-03) | ||
|
||
It comes as a single binary with no additional dependencies and requires only experience with a terminal. | ||
|
||
Simply download the latest binary [from the releases section](https://github.com/Hypfer/valetudo-helper-miioota/releases) | ||
and execute it in a terminal/powershell window. | ||
|
||
|
||
|
||
## Valetudo helpers | ||
|
||
Valetudo helpers are a series of small standalone self-contained single-purpose single-file tools built to make | ||
usage and/or installation of Valetudo a bit easier. | ||
|
||
As with everything Valetudo, some intermediate computer skills are required. You should know what a network is, | ||
what HTTP is, how a terminal works and that kind of stuff. | ||
Please understand that it's not feasible for this or any open source project to provide basic computer lessons. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
const { Command } = require('commander'); | ||
const aioInstallCommand = require("./commands/aioinstall"); | ||
|
||
|
||
const program = new Command(); | ||
|
||
program | ||
.name('valetudo-helper-miioota') | ||
.description('CLI tool to install firmwares via miio local OTA') | ||
.version('2022.04.0'); | ||
|
||
|
||
program.command('install-firmware') | ||
.description('Install a rooted firmware on an unprovisioned robot') | ||
.argument('<filename>', 'path to the rooted firmware image .pkg') | ||
.action((filePath) => { | ||
aioInstallCommand(filePath).catch(err => { | ||
console.error("Error during execution of install command", err); | ||
process.exit(-1); | ||
}) | ||
}); | ||
|
||
program.parse(); |
Oops, something went wrong.