diff --git a/gulpfile.js b/gulpfile.js index b9f5256..b5b2c5b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -2,16 +2,16 @@ * ioBroker gulpfile * Date: 2019-01-28 */ -"use strict"; +'use strict'; -const gulp = require("gulp"); -const fs = require("fs"); -const pkg = require("./package.json"); -const iopackage = require("./io-package.json"); -const version = (pkg && pkg.version) ? pkg.version : iopackage.common.version; -const fileName = "words.js"; -const EMPTY = ""; -const translate = require("./lib/tools").translateText; +const gulp = require('gulp'); +const fs = require('fs'); +const pkg = require('./package.json'); +const iopackage = require('./io-package.json'); +const version = pkg && pkg.version ? pkg.version : iopackage.common.version; +const fileName = 'words.js'; +const EMPTY = ''; +const translate = require('./lib/tools').translateText; const languages = { en: {}, de: {}, @@ -22,38 +22,37 @@ const languages = { it: {}, es: {}, pl: {}, - "zh-cn": {} + 'zh-cn': {}, }; function lang2data(lang) { - let str ="{\n"; + let str = '{\n'; let count = 0; for (const w in lang) { if (lang.hasOwnProperty(w)) { count++; - const key = ' "' + w.replace(/"/g, '\\"') + '": '; - str += key + '"' + lang[w].replace(/"/g, '\\"') + '",\n'; + const key = ` "${w.replace(/"/g, '\\"')}": `; + str += `${key}"${lang[w].replace(/"/g, '\\"')}",\n`; } } if (!count) { - return "{\n}"; - } else { - return str.substring(0, str.length - 2) + "\n}"; + return '{\n}'; } + return `${str.substring(0, str.length - 2)}\n}`; } function readWordJs(src) { try { let words; - if (fs.existsSync(src + "js/" + fileName)) { - words = fs.readFileSync(src + "js/" + fileName).toString(); + if (fs.existsSync(`${src}js/${fileName}`)) { + words = fs.readFileSync(`${src}js/${fileName}`).toString(); } else { words = fs.readFileSync(src + fileName).toString(); } - words = words.substring(words.indexOf("{"), words.length); - words = words.substring(0, words.lastIndexOf(";")); + words = words.substring(words.indexOf('{'), words.length); + words = words.substring(0, words.lastIndexOf(';')); - const resultFunc = new Function("return " + words + ";"); + const resultFunc = new Function(`return ${words};`); return resultFunc(); } catch (e) { @@ -62,35 +61,35 @@ function readWordJs(src) { } function padRight(text, totalLength) { - return text + (text.length < totalLength ? new Array(totalLength - text.length).join(" ") : ""); + return text + (text.length < totalLength ? new Array(totalLength - text.length).join(' ') : ''); } function writeWordJs(data, src) { - let text = ""; - text += "/*global systemDictionary:true */\n"; + let text = ''; + text += '/*global systemDictionary:true */\n'; text += "'use strict';\n\n"; - text += "systemDictionary = {\n"; + text += 'systemDictionary = {\n'; for (const word in data) { if (data.hasOwnProperty(word)) { - text += " " + padRight('"' + word.replace(/"/g, '\\"') + '": {', 50); - let line = ""; + text += ` ${padRight(`"${word.replace(/"/g, '\\"')}": {`, 50)}`; + let line = ''; for (const lang in data[word]) { if (data[word].hasOwnProperty(lang)) { - line += '"' + lang + '": "' + padRight(data[word][lang].replace(/"/g, '\\"') + '",', 50) + " "; + line += `"${lang}": "${padRight(`${data[word][lang].replace(/"/g, '\\"')}",`, 50)} `; } } if (line) { line = line.trim(); line = line.substring(0, line.length - 1); } - text += line + "},\n"; + text += `${line}},\n`; } } - text += "};"; - if (fs.existsSync(src + "js/" + fileName)) { - fs.writeFileSync(src + "js/" + fileName, text); + text += '};'; + if (fs.existsSync(`${src}js/${fileName}`)) { + fs.writeFileSync(`${src}js/${fileName}`, text); } else { - fs.writeFileSync(src + "" + fileName, text); + fs.writeFileSync(`${src}${fileName}`, text); } } @@ -113,31 +112,32 @@ function words2languages(src) { } } } - if (!fs.existsSync(src + "i18n/")) { - fs.mkdirSync(src + "i18n/"); + if (!fs.existsSync(`${src}i18n/`)) { + fs.mkdirSync(`${src}i18n/`); } for (const l in langs) { - if (!langs.hasOwnProperty(l)) + if (!langs.hasOwnProperty(l)) { continue; + } const keys = Object.keys(langs[l]); keys.sort(); const obj = {}; for (let k = 0; k < keys.length; k++) { obj[keys[k]] = langs[l][keys[k]]; } - if (!fs.existsSync(src + "i18n/" + l)) { - fs.mkdirSync(src + "i18n/" + l); + if (!fs.existsSync(`${src}i18n/${l}`)) { + fs.mkdirSync(`${src}i18n/${l}`); } - fs.writeFileSync(src + "i18n/" + l + "/translations.json", lang2data(obj)); + fs.writeFileSync(`${src}i18n/${l}/translations.json`, lang2data(obj)); } } else { - console.error("Cannot read or parse " + fileName); + console.error(`Cannot read or parse ${fileName}`); } } function languages2words(src) { - const dirs = fs.readdirSync(src + "i18n/"); + const dirs = fs.readdirSync(`${src}i18n/`); const langs = {}; const bigOne = {}; const order = Object.keys(languages); @@ -145,27 +145,31 @@ function languages2words(src) { const posA = order.indexOf(a); const posB = order.indexOf(b); if (posA === -1 && posB === -1) { - if (a > b) + if (a > b) { return 1; - if (a < b) + } + if (a < b) { return -1; + } return 0; } else if (posA === -1) { return -1; } else if (posB === -1) { return 1; - } else { - if (posA > posB) - return 1; - if (posA < posB) - return -1; - return 0; } + if (posA > posB) { + return 1; + } + if (posA < posB) { + return -1; + } + return 0; }); for (const lang of dirs) { - if (lang === "flat.txt") + if (lang === 'flat.txt') { continue; - langs[lang] = fs.readFileSync(src + "i18n/" + lang + "/translations.json").toString(); + } + langs[lang] = fs.readFileSync(`${src}i18n/${lang}/translations.json`).toString(); langs[lang] = JSON.parse(langs[lang]); const words = langs[lang]; for (const word in words) { @@ -180,32 +184,32 @@ function languages2words(src) { // read actual words.js const aWords = readWordJs(); - const temporaryIgnore = ["flat.txt"]; + const temporaryIgnore = ['flat.txt']; if (aWords) { // Merge words together for (const w in aWords) { if (aWords.hasOwnProperty(w)) { if (!bigOne[w]) { - console.warn("Take from actual words.js: " + w); + console.warn(`Take from actual words.js: ${w}`); bigOne[w] = aWords[w]; } dirs.forEach(function (lang) { - if (temporaryIgnore.indexOf(lang) !== -1) + if (temporaryIgnore.indexOf(lang) !== -1) { return; + } if (!bigOne[w][lang]) { - console.warn('Missing "' + lang + '": ' + w); + console.warn(`Missing "${lang}": ${w}`); } }); } } - } writeWordJs(bigOne, src); } async function translateNotExisting(obj, baseText, yandex) { - let t = obj["en"]; + let t = obj['en']; if (!t) { t = baseText; } @@ -215,7 +219,7 @@ async function translateNotExisting(obj, baseText, yandex) { if (!obj[l]) { const time = new Date().getTime(); obj[l] = await translate(t, l, yandex); - console.log("en -> " + l + " " + (new Date().getTime() - time) + " ms"); + console.log(`en -> ${l} ${new Date().getTime() - time} ms`); } } } @@ -223,17 +227,17 @@ async function translateNotExisting(obj, baseText, yandex) { //TASKS -gulp.task("adminWords2languages", function (done) { - words2languages("./admin/"); +gulp.task('adminWords2languages', function (done) { + words2languages('./admin/'); done(); }); -gulp.task("adminLanguages2words", function (done) { - languages2words("./admin/"); +gulp.task('adminLanguages2words', function (done) { + languages2words('./admin/'); done(); }); -gulp.task("updatePackages", function (done) { +gulp.task('updatePackages', function (done) { iopackage.common.version = pkg.version; iopackage.common.news = iopackage.common.news || {}; if (!iopackage.common.news[pkg.version]) { @@ -241,97 +245,98 @@ gulp.task("updatePackages", function (done) { const newNews = {}; newNews[pkg.version] = { - en: "news", - de: "neues", - ru: "новое", - pt: "novidades", - nl: "nieuws", - fr: "nouvelles", - it: "notizie", - es: "noticias", - pl: "nowości", - "zh-cn": "新" + en: 'news', + de: 'neues', + ru: 'новое', + pt: 'novidades', + nl: 'nieuws', + fr: 'nouvelles', + it: 'notizie', + es: 'noticias', + pl: 'nowości', + 'zh-cn': '新', }; iopackage.common.news = Object.assign(newNews, news); } - fs.writeFileSync("io-package.json", JSON.stringify(iopackage, null, 4)); + fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4)); done(); }); -gulp.task("updateReadme", function (done) { - const readme = fs.readFileSync("README.md").toString(); - const pos = readme.indexOf("## Changelog\n"); +gulp.task('updateReadme', function (done) { + const readme = fs.readFileSync('README.md').toString(); + const pos = readme.indexOf('## Changelog\n'); if (pos !== -1) { - const readmeStart = readme.substring(0, pos + "## Changelog\n".length); - const readmeEnd = readme.substring(pos + "## Changelog\n".length); + const readmeStart = readme.substring(0, pos + '## Changelog\n'.length); + const readmeEnd = readme.substring(pos + '## Changelog\n'.length); if (readme.indexOf(version) === -1) { const timestamp = new Date(); - const date = timestamp.getFullYear() + "-" + - ("0" + (timestamp.getMonth() + 1).toString(10)).slice(-2) + "-" + - ("0" + (timestamp.getDate()).toString(10)).slice(-2); + const date = `${timestamp.getFullYear()}-${`0${(timestamp.getMonth() + 1).toString(10)}`.slice(-2)}-${`0${timestamp.getDate().toString(10)}`.slice( + -2, + )}`; - let news = ""; + let news = ''; if (iopackage.common.news && iopackage.common.news[pkg.version]) { - news += "* " + iopackage.common.news[pkg.version].en; + news += `* ${iopackage.common.news[pkg.version].en}`; } - fs.writeFileSync("README.md", readmeStart + "### " + version + " (" + date + ")\n" + (news ? news + "\n\n" : "\n") + readmeEnd); + fs.writeFileSync( + 'README.md', + `${readmeStart}### ${version} (${date})\n${news ? `${news}\n\n` : '\n'}${readmeEnd}`, + ); } } done(); }); -gulp.task("translate", async function (done) { - +gulp.task('translate', async function (done) { let yandex; - const i = process.argv.indexOf("--yandex"); + const i = process.argv.indexOf('--yandex'); if (i > -1) { yandex = process.argv[i + 1]; } if (iopackage && iopackage.common) { if (iopackage.common.news) { - console.log("Translate News"); + console.log('Translate News'); for (let k in iopackage.common.news) { - console.log("News: " + k); + console.log(`News: ${k}`); let nw = iopackage.common.news[k]; await translateNotExisting(nw, null, yandex); } } if (iopackage.common.titleLang) { - console.log("Translate Title"); + console.log('Translate Title'); await translateNotExisting(iopackage.common.titleLang, iopackage.common.title, yandex); } if (iopackage.common.desc) { - console.log("Translate Description"); + console.log('Translate Description'); await translateNotExisting(iopackage.common.desc, null, yandex); } - if (fs.existsSync("./admin/i18n/en/translations.json")) { - let enTranslations = require("./admin/i18n/en/translations.json"); + if (fs.existsSync('./admin/i18n/en/translations.json')) { + let enTranslations = require('./admin/i18n/en/translations.json'); for (let l in languages) { - console.log("Translate Text: " + l); + console.log(`Translate Text: ${l}`); let existing = {}; - if (fs.existsSync("./admin/i18n/" + l + "/translations.json")) { - existing = require("./admin/i18n/" + l + "/translations.json"); + if (fs.existsSync(`./admin/i18n/${l}/translations.json`)) { + existing = require(`./admin/i18n/${l}/translations.json`); } for (let t in enTranslations) { if (!existing[t]) { existing[t] = await translate(enTranslations[t], l, yandex); } } - if (!fs.existsSync("./admin/i18n/" + l + "/")) { - fs.mkdirSync("./admin/i18n/" + l + "/"); + if (!fs.existsSync(`./admin/i18n/${l}/`)) { + fs.mkdirSync(`./admin/i18n/${l}/`); } - fs.writeFileSync("./admin/i18n/" + l + "/translations.json", JSON.stringify(existing, null, 4)); + fs.writeFileSync(`./admin/i18n/${l}/translations.json`, JSON.stringify(existing, null, 4)); } } - } - fs.writeFileSync("io-package.json", JSON.stringify(iopackage, null, 4)); + fs.writeFileSync('io-package.json', JSON.stringify(iopackage, null, 4)); }); -gulp.task("translateAndUpdateWordsJS", gulp.series("translate", "adminLanguages2words", "adminWords2languages")); +gulp.task('translateAndUpdateWordsJS', gulp.series('translate', 'adminLanguages2words', 'adminWords2languages')); -gulp.task("default", gulp.series("updatePackages", "updateReadme")); \ No newline at end of file +gulp.task('default', gulp.series('updatePackages', 'updateReadme')); diff --git a/lib/tools.js b/lib/tools.js index e75a67d..399ce28 100644 --- a/lib/tools.js +++ b/lib/tools.js @@ -1,66 +1,71 @@ -const axios = require("axios").default; +const axios = require('axios').default; /** * Tests whether the given variable is a real object and not an Array - * @param {any} it The variable to test - * @returns {it is Record} + * + * @param it The variable to test + * @returns */ function isObject(it) { // This is necessary because: // typeof null === 'object' // typeof [] === 'object' // [] instanceof Object === true - return Object.prototype.toString.call(it) === "[object Object]"; + return Object.prototype.toString.call(it) === '[object Object]'; } /** * Tests whether the given variable is really an Array - * @param {any} it The variable to test - * @returns {it is any[]} + * + * @param it The variable to test + * @returns */ function isArray(it) { - if (typeof Array.isArray === "function") return Array.isArray(it); - return Object.prototype.toString.call(it) === "[object Array]"; + if (typeof Array.isArray === 'function') { + return Array.isArray(it); + } + return Object.prototype.toString.call(it) === '[object Array]'; } /** * Translates text to the target language. Automatically chooses the right translation API. - * @param {string} text The text to translate - * @param {string} targetLang The target languate - * @param {string} [yandexApiKey] The yandex API key. You can create one for free at https://translate.yandex.com/developers - * @returns {Promise} + * + * @param text The text to translate + * @param targetLang The target languate + * @param [yandexApiKey] The yandex API key. You can create one for free at https://translate.yandex.com/developers + * @returns */ async function translateText(text, targetLang, yandexApiKey) { - if (targetLang === "en") { + if (targetLang === 'en') { return text; } else if (!text) { - return ""; + return ''; } if (yandexApiKey) { return translateYandex(text, targetLang, yandexApiKey); - } else { - return translateGoogle(text, targetLang); } + return translateGoogle(text, targetLang); } /** * Translates text with Yandex API - * @param {string} text The text to translate - * @param {string} targetLang The target languate - * @param {string} apiKey The yandex API key. You can create one for free at https://translate.yandex.com/developers - * @returns {Promise} + * + * @param text The text to translate + * @param targetLang The target languate + * @param apiKey The yandex API key. You can create one for free at https://translate.yandex.com/developers + * @returns */ async function translateYandex(text, targetLang, apiKey) { - if (targetLang === "zh-cn") { - targetLang = "zh"; + if (targetLang === 'zh-cn') { + targetLang = 'zh'; } try { const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`; - const response = await axios({url, timeout: 15000}); + const response = await axios({ url, timeout: 15000 }); if (response.data && response.data.text && isArray(response.data.text)) { return response.data.text[0]; } - throw new Error("Invalid response for translate request"); + throw new Error('Invalid response for translate request'); } catch (e) { throw new Error(`Could not translate to "${targetLang}": ${e}`); } @@ -68,24 +73,23 @@ async function translateYandex(text, targetLang, apiKey) { /** * Translates text with Google API - * @param {string} text The text to translate - * @param {string} targetLang The target languate - * @returns {Promise} + * + * @param text The text to translate + * @param targetLang The target languate + * @returns */ async function translateGoogle(text, targetLang) { try { const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`; - const response = await axios({url, timeout: 15000}); + const response = await axios({ url, timeout: 15000 }); if (isArray(response.data)) { // we got a valid response return response.data[0][0][0]; } - throw new Error("Invalid response for translate request"); + throw new Error('Invalid response for translate request'); } catch (e) { if (e.response && e.response.status === 429) { - throw new Error( - `Could not translate to "${targetLang}": Rate-limited by Google Translate` - ); + throw new Error(`Could not translate to "${targetLang}": Rate-limited by Google Translate`); } else { throw new Error(`Could not translate to "${targetLang}": ${e}`); } @@ -95,5 +99,5 @@ async function translateGoogle(text, targetLang) { module.exports = { isArray, isObject, - translateText + translateText, }; diff --git a/main.js b/main.js index c8ef4e4..400319a 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; /* * Created with @iobroker/create-adapter v1.31.0 @@ -9,23 +9,21 @@ // The adapter-core module gives you access to the core ioBroker functions // you need to create an adapter -const utils = require("@iobroker/adapter-core"); // Get common adapter utils -const crc = require("crc"); +const utils = require('@iobroker/adapter-core'); // Get common adapter utils +const crc = require('crc'); //const ioBLib = require('strathcole/iob-lib').ioBLib; -const net = require("net"); +const net = require('net'); const IPClient = new net.Socket(); - // Load your modules here, e.g.: // const fs = require("fs"); /** * The adapter instance - * @type {ioBroker.Adapter} + * */ let adapter; // globale Variablen -/** @type {number | any } */ let myState; // Aktueller Status let hvsSOC; let hvsMaxVolt; @@ -72,8 +70,6 @@ let myNumberforDetails; let ConfTestMode; let FirstRun; - -/** @type {string} */ let hvsSerial; let hvsBMU; let hvsBMUA; @@ -83,7 +79,6 @@ let hvsGrid; let hvsErrorString; let hvsParamT; -/** @type {boolean} */ let ConfBatDetails; /*const myStates = [ @@ -94,38 +89,33 @@ let ConfBatDetails; ];*/ - - -/** @type {NodeJS.Timeout} */ let idInterval1; let idTimeout1; - const myRequests = [ - Buffer.from("010300000066c5e0", "hex"), //0 - Buffer.from("01030500001984cc", "hex"), //1 - Buffer.from("010300100003040e", "hex"), //2 - Buffer.from("0110055000020400018100f853", "hex"), //3 start measuring - Buffer.from("010305510001d517", "hex"), //4 - Buffer.from("01030558004104e5", "hex"), //5 - Buffer.from("01030558004104e5", "hex"), //6 - Buffer.from("01030558004104e5", "hex"), //7 - Buffer.from("01030558004104e5", "hex"), //8 + Buffer.from('010300000066c5e0', 'hex'), //0 + Buffer.from('01030500001984cc', 'hex'), //1 + Buffer.from('010300100003040e', 'hex'), //2 + Buffer.from('0110055000020400018100f853', 'hex'), //3 start measuring + Buffer.from('010305510001d517', 'hex'), //4 + Buffer.from('01030558004104e5', 'hex'), //5 + Buffer.from('01030558004104e5', 'hex'), //6 + Buffer.from('01030558004104e5', 'hex'), //7 + Buffer.from('01030558004104e5', 'hex'), //8 // to read the 5th module, the box must first be reconfigured - Buffer.from("01100100000306444542554700176f", "hex"), //9 switch to second turn for the last few cells - Buffer.from("0110055000020400018100f853", "hex"), //10 start measuring remaining cells (like 3) - Buffer.from("010305510001d517", "hex"), //11 (like 4) - Buffer.from("01030558004104e5", "hex"), //12 (like 5) - Buffer.from("01030558004104e5", "hex"), //13 (like 6) + Buffer.from('01100100000306444542554700176f', 'hex'), //9 switch to second turn for the last few cells + Buffer.from('0110055000020400018100f853', 'hex'), //10 start measuring remaining cells (like 3) + Buffer.from('010305510001d517', 'hex'), //11 (like 4) + Buffer.from('01030558004104e5', 'hex'), //12 (like 5) + Buffer.from('01030558004104e5', 'hex'), //13 (like 6) // The BYD tool also issues two more requests, probably to gather even more cells in some larger setups - Buffer.from("01030558004104e5", "hex"), //14 (like 7) - Buffer.from("01030558004104e5", "hex"), //15 (like 8) + Buffer.from('01030558004104e5', 'hex'), //14 (like 7) + Buffer.from('01030558004104e5', 'hex'), //15 (like 8) // // ONLY if two towers in parallel - Buffer.from("01100550000204000281000853", "hex"), // 16 - Switch to Box 2 -> 281 + Buffer.from('01100550000204000281000853', 'hex'), // 16 - Switch to Box 2 -> 281 ]; - /* Während des Updates des BMS funktioniert das Auslesen offensichtlich nicht, hier die Antworten des Speichers (Seriennummer verfälscht und CRC des ersten Paketes nicht neu berechnet) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 7 8 9 0 1 2 3 4 5 6 7 8 9 0 01 03 cc 50 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 78 78 78 78 78 03 0d 03 0f 03 14 01 00 03 12 02 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 15 04 0c 12 38 2b 82 b2 @@ -135,176 +125,433 @@ const myRequests = [ 5 min. später klappte es wieder und dann war auch die neue F/W-Version in der Antwort enthalten */ const myErrors = [ - "High Temperature Charging (Cells)", - "Low Temperature Charging (Cells)", - "Over Current Discharging", - "Over Current Charging", - "Main circuit Failure", - "Short Current Alarm", - "Cells Imbalance", - "Current Sensor Failure", - "Battery Over Voltage", - "Battery Under Voltage", - "Cell Over Voltage", - "Cell Under Voltage", - "Voltage Sensor Failure", - "Temperature Sensor Failure", - "High Temperature Discharging (Cells)", - "Low Temperature Discharging (Cells)" + 'High Temperature Charging (Cells)', + 'Low Temperature Charging (Cells)', + 'Over Current Discharging', + 'Over Current Charging', + 'Main circuit Failure', + 'Short Current Alarm', + 'Cells Imbalance', + 'Current Sensor Failure', + 'Battery Over Voltage', + 'Battery Under Voltage', + 'Cell Over Voltage', + 'Cell Under Voltage', + 'Voltage Sensor Failure', + 'Temperature Sensor Failure', + 'High Temperature Discharging (Cells)', + 'Low Temperature Discharging (Cells)', ]; -const byd_stat_tower = [ - "Battery Over Voltage", // Bit 0 - "Battery Under Voltage", // Bit 1 - "Cells OverVoltage", // Bit 2 - "Cells UnderVoltage", // Bit 3 - "Cells Imbalance", // Bit 4 - "Charging High Temperature(Cells)", // Bit 5 - "Charging Low Temperature(Cells)", // Bit 6 - "DisCharging High Temperature(Cells)", // Bit 7 - "DisCharging Low Temperature(Cells)", // Bit 8 - "Charging OverCurrent(Cells)", // Bit 9 - "DisCharging OverCurrent(Cells)", // Bit 10 - "Charging OverCurrent(Hardware)", // Bit 11 - "Short Circuit", // Bit 12 - "Inversly Connection", // Bit 13 - "Interlock switch Abnormal", // Bit 14 - "AirSwitch Abnormal" // Bit 15 -] +/* const byd_stat_tower = [ + 'Battery Over Voltage', // Bit 0 + 'Battery Under Voltage', // Bit 1 + 'Cells OverVoltage', // Bit 2 + 'Cells UnderVoltage', // Bit 3 + 'Cells Imbalance', // Bit 4 + 'Charging High Temperature(Cells)', // Bit 5 + 'Charging Low Temperature(Cells)', // Bit 6 + 'DisCharging High Temperature(Cells)', // Bit 7 + 'DisCharging Low Temperature(Cells)', // Bit 8 + 'Charging OverCurrent(Cells)', // Bit 9 + 'DisCharging OverCurrent(Cells)', // Bit 10 + 'Charging OverCurrent(Hardware)', // Bit 11 + 'Short Circuit', // Bit 12 + 'Inversly Connection', // Bit 13 + 'Interlock switch Abnormal', // Bit 14 + 'AirSwitch Abnormal', // Bit 15 +];*/ const myINVs = [ - "Fronius HV", //0 - "Goodwe HV", //1 - "Fronius HV", //2 - "Kostal HV", //3 - "Goodwe HV", //4 - "SMA SBS3.7/5.0", //5 - "Kostal HV", //6 - "SMA SBS3.7/5.0", //7 - "Sungrow HV", //8 - "Sungrow HV", //9 - "Kaco HV", //10 - "Kaco HV", //11 - "Ingeteam HV", //12 - "Ingeteam HV", //13 - "SMA SBS 2.5 HV", //14 - "undefined", //15 - "SMA SBS 2.5 HV", //16 - "Fronius HV", //17 - "undefined", //18 - "SMA STP" //19 + 'Fronius HV', //0 + 'Goodwe HV', //1 + 'Fronius HV', //2 + 'Kostal HV', //3 + 'Goodwe HV', //4 + 'SMA SBS3.7/5.0', //5 + 'Kostal HV', //6 + 'SMA SBS3.7/5.0', //7 + 'Sungrow HV', //8 + 'Sungrow HV', //9 + 'Kaco HV', //10 + 'Kaco HV', //11 + 'Ingeteam HV', //12 + 'Ingeteam HV', //13 + 'SMA SBS 2.5 HV', //14 + 'undefined', //15 + 'SMA SBS 2.5 HV', //16 + 'Fronius HV', //17 + 'undefined', //18 + 'SMA STP', //19 ]; const myINVsLVS = [ - "Fronius HV", - "Goodwe HV", - "Goodwe HV", - "Kostal HV", - "Selectronic LV", - "SMA SBS3.7/5.0", - "SMA LV", - "Victron LV", - "Suntech LV", - "Sungrow HV", - "Kaco HV", - "Studer LV", - "Solar Edge LV", - "Ingeteam HV", - "Sungrow LV", - "Schneider LV", - "SMA SBS2.5 HV", - "Solar Edge LV", - "Solar Edge LV", - "Solar Edge LV", - "unknown" + 'Fronius HV', + 'Goodwe HV', + 'Goodwe HV', + 'Kostal HV', + 'Selectronic LV', + 'SMA SBS3.7/5.0', + 'SMA LV', + 'Victron LV', + 'Suntech LV', + 'Sungrow HV', + 'Kaco HV', + 'Studer LV', + 'Solar Edge LV', + 'Ingeteam HV', + 'Sungrow LV', + 'Schneider LV', + 'SMA SBS2.5 HV', + 'Solar Edge LV', + 'Solar Edge LV', + 'Solar Edge LV', + 'unknown', ]; - -const myBattTypes = [ - "HVL", - "HVM", - "HVS" -]; -/* HVM: 16 cells per module - HVS: 32 cells per module - HVL: unknown so I count 0 cells per module +/* +const myBattTypes = ['HVL', 'HVM', 'HVS']; + HVM: 16 cells per module + HVS: 32 cells per module + HVL: unknown so I count 0 cells per module */ /** - * Starts the adapter instance - * @param {Partial} [options] + * Starts the adapter with the given options. + * + * @param [options] - The options to configure the adapter. + * @returns The created adapter instance. */ function startAdapter(options) { // Create the adapter and define its methods - return adapter = utils.adapter(Object.assign({}, options, { - name: "bydhvs", - - // The ready callback is called when databases are connected and adapter received configuration. - // start here! - ready: main, // Main method defined below for readability - - // is called when adapter shuts down - callback has to be called under any circumstances! - unload: (callback) => { - adapter.log.silly("got unload event"); - try { - clearInterval(idInterval1); - clearTimeout(idTimeout1); - stopPoll(); - IPClient.destroy(); + return (adapter = utils.adapter( + Object.assign({}, options, { + name: 'bydhvs', + + /** + * The ready callback is called when databases are connected and adapter received configuration. + * Start here! + */ + ready: main, // Main method defined below for readability + + /** + * Called when the adapter shuts down. The callback has to be called under any circumstances. + * + * @param callback - The callback to be called when the unload process is complete. + */ + unload: callback => { + adapter.log.silly('got unload event'); + try { + clearInterval(idInterval1); + clearTimeout(idTimeout1); + stopPoll(); + IPClient.destroy(); - callback(); - } catch (e) { - callback(); - } - }, - })); + callback(); + } catch { + callback(); + } + }, + }), + )); } - function setObjectsCells() { //Diagnose-data only if necessary. let myObjects = []; - let ObjTowerString = ""; + let ObjTowerString = ''; - for(let towerNumber = 0; towerNumber < ConfBydTowerCount; towerNumber++) { + for (let towerNumber = 0; towerNumber < ConfBydTowerCount; towerNumber++) { if (ConfBydTowerCount > 1) { - ObjTowerString = ".Tower_" +(towerNumber + 1); + ObjTowerString = `.Tower_${towerNumber + 1}`; } myObjects = [ - ["Diagnosis"+ ObjTowerString + ".mVoltMax", "state", "Max Cell Voltage (mv)", "number", "value.voltage", true, false, "mV"], - ["Diagnosis"+ ObjTowerString + ".mVoltMin", "state", "Min Cell Voltage (mv)", "number", "value.voltage", true, false, "mV"], - ["Diagnosis"+ ObjTowerString + ".mVoltMaxCell", "state", "Max Cell Volt (Cellnr)", "number", "value.voltage", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".mVoltMinCell", "state", "Min Cell Volt (Cellnr)", "number", "value.voltage", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".TempMaxCell", "state", "Max Cell Temp (Cellnr)", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".TempMinCell", "state", "Min Cell Temp(Cellnr)", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".mVoltDefDeviation", "state", "default deviation of the cells", "number", "value.battery", true, false, "mV"], - ["Diagnosis"+ ObjTowerString + ".TempDefDeviation", "state", "default deviation of the cells", "number", "value.temperature", true, false, "°C"], - ["Diagnosis"+ ObjTowerString + ".mVoltMean", "state", "mean of the cells", "number", "value.temperature", true, false, "mV"], - ["Diagnosis"+ ObjTowerString + ".TempMean", "state", "mean of the cells", "number", "value.temperature", true, false, "°C"], - ["Diagnosis"+ ObjTowerString + ".mVoltGt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".mVoltLt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".TempGt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".TempLt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".ChargeTotal", "state", "Total Charge in that tower", "number", "value.watt", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".DischargeTotal", "state", "Total Discharge in that tower", "number", "value.watt", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".ETA", "state", "Wirkungsgrad of that tower", "number", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".BatteryVolt", "state", "Wirkungsgrad of that tower", "number", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".OutVolt", "state", "Output voltage", "number", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".SOC", "state", "SOC (Diagnosis)", "number", "value.battery", true, false, "%"], - ["Diagnosis"+ ObjTowerString + ".mVoltDefDeviation", "state", "default deviation of the cells", "number", "value.battery", true, false, "mV"], - ["Diagnosis"+ ObjTowerString + ".TempDefDeviation", "state", "default deviation of the cells", "number", "value.temperature", true, false, "°C"], - ["Diagnosis"+ ObjTowerString + ".mVoltMean", "state", "mean of the cells", "number", "value.temperature", true, false, "mV"], - ["Diagnosis"+ ObjTowerString + ".TempMean", "state", "mean of the cells", "number", "value.temperature", true, false, "°C"], - ["Diagnosis"+ ObjTowerString + ".mVoltGt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".mVoltLt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".TempGt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".TempLt150DefVar", "state", "mean of the cells", "number", "value.temperature", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".SOH", "state", "State of Health", "number", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".State", "state", "tower state", "string", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".BalancingOne", "state", "tower state", "string", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".BalancingTwo", "state", "tower state", "string", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".BalancingCountOne", "state", "tower state", "number", "value", true, false, ""], - ["Diagnosis"+ ObjTowerString + ".BalancingCountTwo", "state", "tower state", "number", "value", true, false, ""], + [ + `Diagnosis${ObjTowerString}.mVoltMax`, + 'state', + 'Max Cell Voltage (mv)', + 'number', + 'value.voltage', + true, + false, + 'mV', + ], + [ + `Diagnosis${ObjTowerString}.mVoltMin`, + 'state', + 'Min Cell Voltage (mv)', + 'number', + 'value.voltage', + true, + false, + 'mV', + ], + [ + `Diagnosis${ObjTowerString}.mVoltMaxCell`, + 'state', + 'Max Cell Volt (Cellnr)', + 'number', + 'value.voltage', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.mVoltMinCell`, + 'state', + 'Min Cell Volt (Cellnr)', + 'number', + 'value.voltage', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.TempMaxCell`, + 'state', + 'Max Cell Temp (Cellnr)', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.TempMinCell`, + 'state', + 'Min Cell Temp(Cellnr)', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.mVoltDefDeviation`, + 'state', + 'default deviation of the cells', + 'number', + 'value.battery', + true, + false, + 'mV', + ], + [ + `Diagnosis${ObjTowerString}.TempDefDeviation`, + 'state', + 'default deviation of the cells', + 'number', + 'value.temperature', + true, + false, + '°C', + ], + [ + `Diagnosis${ObjTowerString}.mVoltMean`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + 'mV', + ], + [ + `Diagnosis${ObjTowerString}.TempMean`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '°C', + ], + [ + `Diagnosis${ObjTowerString}.mVoltGt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.mVoltLt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.TempGt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.TempLt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.ChargeTotal`, + 'state', + 'Total Charge in that tower', + 'number', + 'value.watt', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.DischargeTotal`, + 'state', + 'Total Discharge in that tower', + 'number', + 'value.watt', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.ETA`, + 'state', + 'Wirkungsgrad of that tower', + 'number', + 'value', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.BatteryVolt`, + 'state', + 'Wirkungsgrad of that tower', + 'number', + 'value', + true, + false, + '', + ], + [`Diagnosis${ObjTowerString}.OutVolt`, 'state', 'Output voltage', 'number', 'value', true, false, ''], + [`Diagnosis${ObjTowerString}.SOC`, 'state', 'SOC (Diagnosis)', 'number', 'value.battery', true, false, '%'], + [ + `Diagnosis${ObjTowerString}.mVoltDefDeviation`, + 'state', + 'default deviation of the cells', + 'number', + 'value.battery', + true, + false, + 'mV', + ], + [ + `Diagnosis${ObjTowerString}.TempDefDeviation`, + 'state', + 'default deviation of the cells', + 'number', + 'value.temperature', + true, + false, + '°C', + ], + [ + `Diagnosis${ObjTowerString}.mVoltMean`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + 'mV', + ], + [ + `Diagnosis${ObjTowerString}.TempMean`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '°C', + ], + [ + `Diagnosis${ObjTowerString}.mVoltGt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.mVoltLt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.TempGt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.TempLt150DefVar`, + 'state', + 'mean of the cells', + 'number', + 'value.temperature', + true, + false, + '', + ], + [`Diagnosis${ObjTowerString}.SOH`, 'state', 'State of Health', 'number', 'value', true, false, ''], + [`Diagnosis${ObjTowerString}.State`, 'state', 'tower state', 'string', 'value', true, false, ''], + [`Diagnosis${ObjTowerString}.BalancingOne`, 'state', 'tower state', 'string', 'value', true, false, ''], + [`Diagnosis${ObjTowerString}.BalancingTwo`, 'state', 'tower state', 'string', 'value', true, false, ''], + [ + `Diagnosis${ObjTowerString}.BalancingCountOne`, + 'state', + 'tower state', + 'number', + 'value', + true, + false, + '', + ], + [ + `Diagnosis${ObjTowerString}.BalancingCountTwo`, + 'state', + 'tower state', + 'number', + 'value', + true, + false, + '', + ], ]; for (let i = 0; i < myObjects.length; i++) { @@ -318,7 +565,7 @@ function setObjectsCells() { write: myObjects[i][6], unit: myObjects[i][7], }, - native: {} + native: {}, }); } for (let i = 0; i < myObjects.length; i++) { @@ -326,84 +573,83 @@ function setObjectsCells() { checkandrepairUnit(myObjects[i][0], myObjects[i][7], myObjects[i][5]); } - for (let i = 1; i <= hvsNumCells; i++) { - adapter.setObjectNotExists(`CellDetails`+ObjTowerString +`.CellVolt` + pad(i, 3), { - type: "state", + adapter.setObjectNotExists(`CellDetails${ObjTowerString}.CellVolt${pad(i, 3)}`, { + type: 'state', common: { - name: "Voltage Cell: " + pad(i, 3), - type: "number", - role: "value.voltage", + name: `Voltage Cell: ${pad(i, 3)}`, + type: 'number', + role: 'value.voltage', read: true, write: false, - unit: "mV" + unit: 'mV', }, - native: {} + native: {}, }); - checkandrepairUnit(`CellDetails`+ObjTowerString +`.CellVolt` + pad(i, 3), "mV", "value.voltage"); //repair forgotten units in first version + checkandrepairUnit(`CellDetails${ObjTowerString}.CellVolt${pad(i, 3)}`, 'mV', 'value.voltage'); //repair forgotten units in first version for (let i = 1; i <= hvsNumTemps; i++) { - adapter.setObjectNotExists(`CellDetails`+ObjTowerString +`.CellTemp` + pad(i, 3), { - type: "state", + adapter.setObjectNotExists(`CellDetails${ObjTowerString}.CellTemp${pad(i, 3)}`, { + type: 'state', common: { - name: "Temp Cell: " + pad(i, 3), - type: "number", - role: "value.temperature", + name: `Temp Cell: ${pad(i, 3)}`, + type: 'number', + role: 'value.temperature', read: true, write: false, - unit: "°C" + unit: '°C', }, - native: {} + native: {}, }); - checkandrepairUnit(`CellDetails`+ObjTowerString +`.CellTemp` + pad(i, 3), "°C", "value.temperature"); //repair forgotten units in first version + checkandrepairUnit(`CellDetails${ObjTowerString}.CellTemp${pad(i, 3)}`, '°C', 'value.temperature'); //repair forgotten units in first version } } } - } function setObjects() { let myObjects = [ - ["System.Serial", "state", "Serial number", "string", "text", true, false, ""], - ["System.BMU", "state", "F/W BMU", "string", "text", true, false, ""], - ["System.BMS", "state", "F/W BMS", "string", "text", true, false, ""], - ["System.BMUBankA", "state", "F/W BMU-BankA", "string", "text", true, false, ""], - ["System.BMUBankB", "state", "F/W BMU-BankB", "string", "text", true, false, ""], - ["System.Modules", "state", "modules (count)", "number", "value", true, false, ""], - ["System.Towers", "state", "towers (count)", "number", "value", true, false, ""], - ["System.Grid", "state", "Parameter Table", "string", "text", true, false, ""], - ["System.ParamT", "state", "F/W BMU", "string", "text", true, false, ""], - ["System.BattType", "state", "Battery Type", "string", "text", true, false, ""], - ["System.InvType", "state", "Inverter Type", "string", "text", true, false, ""], - ["State.SOC", "state", "SOC", "number", "value.battery", true, false, "%"], - ["State.VoltMax", "state", "Max Cell Voltage", "number", "value.voltage", true, false, "V"], - ["State.VoltMin", "state", "Min Cell Voltage", "number", "value.voltage", true, false, "V"], - ["State.SOH", "state", "SOH", "number", "value.battery", true, false, "%"], - ["State.Current", "state", "Charge / Discharge Current", "number", "value.current", true, false, "A"], - ["State.Power_Consumption", "state", "Charge Power", "number", "value.power", true, false, "W"], - ["State.Power_Delivery", "state", "Discharge Power", "number", "value.power", true, false, "W"], - ["State.VoltBatt", "state", "Battery Voltage", "number", "value.voltage", true, false, "V"], - ["State.TempMax", "state", "Max Cell Temp", "number", "value.temperature", true, false, "°C"], - ["State.TempMin", "state", "Min Cell Temp", "number", "value.temperature", true, false, "°C"], - ["State.VoltDiff", "state", "Max - Min Cell Voltage", "number", "value.temperature", true, false, "V"], - ["State.Power", "state", "Power", "number", "value.power", true, false, "W"], - ["State.TempBatt", "state", "Battery Temperature", "number", "value.temperature", true, false, "°C"], - ["State.VoltOut", "state", "Output Voltage", "number", "value.voltage", true, false, "V"], - ["System.ErrorNum", "state", "Error (numeric)", "number", "value", true, false, ""], + ['System.Serial', 'state', 'Serial number', 'string', 'text', true, false, ''], + ['System.BMU', 'state', 'F/W BMU', 'string', 'text', true, false, ''], + ['System.BMS', 'state', 'F/W BMS', 'string', 'text', true, false, ''], + ['System.BMUBankA', 'state', 'F/W BMU-BankA', 'string', 'text', true, false, ''], + ['System.BMUBankB', 'state', 'F/W BMU-BankB', 'string', 'text', true, false, ''], + ['System.Modules', 'state', 'modules (count)', 'number', 'value', true, false, ''], + ['System.Towers', 'state', 'towers (count)', 'number', 'value', true, false, ''], + ['System.Grid', 'state', 'Parameter Table', 'string', 'text', true, false, ''], + ['System.ParamT', 'state', 'F/W BMU', 'string', 'text', true, false, ''], + ['System.BattType', 'state', 'Battery Type', 'string', 'text', true, false, ''], + ['System.InvType', 'state', 'Inverter Type', 'string', 'text', true, false, ''], + ['State.SOC', 'state', 'SOC', 'number', 'value.battery', true, false, '%'], + ['State.VoltMax', 'state', 'Max Cell Voltage', 'number', 'value.voltage', true, false, 'V'], + ['State.VoltMin', 'state', 'Min Cell Voltage', 'number', 'value.voltage', true, false, 'V'], + ['State.SOH', 'state', 'SOH', 'number', 'value.battery', true, false, '%'], + ['State.Current', 'state', 'Charge / Discharge Current', 'number', 'value.current', true, false, 'A'], + ['State.Power_Consumption', 'state', 'Charge Power', 'number', 'value.power', true, false, 'W'], + ['State.Power_Delivery', 'state', 'Discharge Power', 'number', 'value.power', true, false, 'W'], + ['State.VoltBatt', 'state', 'Battery Voltage', 'number', 'value.voltage', true, false, 'V'], + ['State.TempMax', 'state', 'Max Cell Temp', 'number', 'value.temperature', true, false, '°C'], + ['State.TempMin', 'state', 'Min Cell Temp', 'number', 'value.temperature', true, false, '°C'], + ['State.VoltDiff', 'state', 'Max - Min Cell Voltage', 'number', 'value.temperature', true, false, 'V'], + ['State.Power', 'state', 'Power', 'number', 'value.power', true, false, 'W'], + ['State.TempBatt', 'state', 'Battery Temperature', 'number', 'value.temperature', true, false, '°C'], + ['State.VoltOut', 'state', 'Output Voltage', 'number', 'value.voltage', true, false, 'V'], + ['System.ErrorNum', 'state', 'Error (numeric)', 'number', 'value', true, false, ''], //["State.ErrorNum", "state", "Error (numeric)", "number", "", true, false, ""], // ERROR ERROR ERROR - ["System.ErrorStr", "state", "Error (string)", "string", "text", true, false, ""], - ["System.ChargeTotal", "state", "Total Charge of the system", "number", "value", true, false, ""], - ["System.DischargeTotal", "state", "Total Discharge of the system", "number", "value", true, false, ""], - ["System.ETA", "state", "Wirkungsgrad der Batterie in percent", "number", "value", true, false, ""], + ['System.ErrorStr', 'state', 'Error (string)', 'string', 'text', true, false, ''], + ['System.ChargeTotal', 'state', 'Total Charge of the system', 'number', 'value', true, false, ''], + ['System.DischargeTotal', 'state', 'Total Discharge of the system', 'number', 'value', true, false, ''], + ['System.ETA', 'state', 'Wirkungsgrad der Batterie in percent', 'number', 'value', true, false, ''], ]; const rawObjects = [ - ["System.Raw_00", "state", "Raw Message of sequence 00", "string", "text", true, false, ""], - ["System.Raw_01", "state", "Raw Message of sequence 01", "string", "text", true, false, ""], - ["System.Raw_02", "state", "Raw Message of sequence 02", "string", "text", true, false, ""], - ] - if(adapter.config.ConfStoreRawMessages) + ['System.Raw_00', 'state', 'Raw Message of sequence 00', 'string', 'text', true, false, ''], + ['System.Raw_01', 'state', 'Raw Message of sequence 01', 'string', 'text', true, false, ''], + ['System.Raw_02', 'state', 'Raw Message of sequence 02', 'string', 'text', true, false, ''], + ]; + if (adapter.config.ConfStoreRawMessages) { myObjects = myObjects.concat(rawObjects); + } for (let i = 0; i < myObjects.length; i++) { adapter.setObjectNotExists(myObjects[i][0], { @@ -416,7 +662,7 @@ function setObjects() { write: myObjects[i][6], unit: myObjects[i][7], //works only for new objects, so check later for existing objects }, - native: {} + native: {}, }); } //repair forgotten units in first version and required roles @@ -434,8 +680,6 @@ function setObjects() { }, 4000);*/ //changeErrorNum(); //not a really good idea but I do not know how to delete -- did not work :-( - - /*async function changeErrorNum() { //did not work, this part created a state with "getObjectAsync" try { @@ -450,47 +694,51 @@ function setObjects() { } }*/ - async function checkandrepairUnit(id, NewUnit, NewRole) { //want to test and understand async and await, so it's introduced here. //check for forgotten unit in first version and if it's missing add unit. try { const obj = await adapter.getObjectAsync(id); - if (NewUnit != "") { + if (NewUnit != '') { if (obj.common.unit != NewUnit) { adapter.extendObject(id, { common: { unit: NewUnit } }); } } - if (obj.common.role == "") { + if (obj.common.role == '') { adapter.extendObject(id, { common: { role: NewRole } }); } - } - catch (err) { + } catch { //dann eben nicht. } } function checkPacket(data) { const byteArray = new Uint8Array(data); - const packetLength = data[2] + 5;// 3 header, 2 crc - if (byteArray[0] != 1) { return false; } - if (byteArray[1] === 3) { //habe die Kodierung der Antwort mit 1 an zweiter Stelle nicht verstanden, daher hier keine Längenprüfung + const packetLength = data[2] + 5; // 3 header, 2 crc + if (byteArray[0] != 1) { + return false; + } + if (byteArray[1] === 3) { + //habe die Kodierung der Antwort mit 1 an zweiter Stelle nicht verstanden, daher hier keine Längenprüfung if (packetLength != byteArray.length) { - return (false); + return false; } } else { - if (byteArray[1] != 16) { return false; } + if (byteArray[1] != 16) { + return false; + } } - return (crc.crc16modbus(byteArray) === 0); + return crc.crc16modbus(byteArray) === 0; } function pad(n, width, z) { - z = z || "0"; - n = n + ""; + z = z || '0'; + n = `${n}`; return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; } -function buf2int16SI(byteArray, pos) { //signed +function buf2int16SI(byteArray, pos) { + //signed let result = 0; result = byteArray[pos] * 256 + byteArray[pos + 1]; if (result > 32768) { @@ -499,55 +747,70 @@ function buf2int16SI(byteArray, pos) { //signed return result; } -function buf2int16US(byteArray, pos) { //unsigned +function buf2int16US(byteArray, pos) { + //unsigned let result = 0; result = byteArray[pos] * 256 + byteArray[pos + 1]; return result; } -function buf2int32US(byteArray, pos) { //unsigned +function buf2int32US(byteArray, pos) { + //unsigned let result = 0; - result = byteArray[pos +2] * 16777216 + byteArray[pos +3] * 65536 + byteArray[pos] * 256 + byteArray[pos + 1]; + result = byteArray[pos + 2] * 16777216 + byteArray[pos + 3] * 65536 + byteArray[pos] * 256 + byteArray[pos + 1]; return result; } function decodePacket0(data) { - if(adapter.config.ConfStoreRawMessages) - adapter.setState("System.Raw_00", data.toString("hex"), true); + if (adapter.config.ConfStoreRawMessages) { + adapter.setState('System.Raw_00', data.toString('hex'), true); + } const byteArray = new Uint8Array(data); // Serialnumber - hvsSerial = ""; + hvsSerial = ''; for (let i = 3; i < 22; i++) { hvsSerial += String.fromCharCode(byteArray[i]); } // Hardwaretype //leider dazugestrickt, wollte in die andere Logik nicht eingreifen - if (byteArray[5] == 51 ) {hvsBattType_fromSerial = "HVS";} - if (byteArray[5] == 50 ) {hvsBattType_fromSerial = "LVS";} - if (byteArray[5] == 49 ) {hvsBattType_fromSerial = "LVS";} + if (byteArray[5] == 51) { + hvsBattType_fromSerial = 'HVS'; + } + if (byteArray[5] == 50) { + hvsBattType_fromSerial = 'LVS'; + } + if (byteArray[5] == 49) { + hvsBattType_fromSerial = 'LVS'; + } // Firmwareversion - hvsBMUA = "V" + byteArray[27].toString() + "." + byteArray[28].toString(); - hvsBMUB = "V" + byteArray[29].toString() + "." + byteArray[30].toString(); + hvsBMUA = `V${byteArray[27].toString()}.${byteArray[28].toString()}`; + hvsBMUB = `V${byteArray[29].toString()}.${byteArray[30].toString()}`; if (byteArray[33] === 0) { - hvsBMU = hvsBMUA + "-A"; + hvsBMU = `${hvsBMUA}-A`; } else { - hvsBMU = hvsBMUB + "-B"; + hvsBMU = `${hvsBMUB}-B`; } - hvsBMS = "V" + byteArray[31].toString() + "." + byteArray[32].toString() + "-" + String.fromCharCode(byteArray[34] + 65); - + hvsBMS = `V${byteArray[31].toString()}.${byteArray[32].toString()}-${String.fromCharCode(byteArray[34] + 65)}`; + // Amount of towers // 1st Byte - Count of towers // 2nd Byte - Amount of Modules (per Tower) hvsModules = parseInt((byteArray[36] % 16).toString()); - hvsTowers = parseInt((Math.floor(byteArray[36] / 16)).toString()); - + hvsTowers = parseInt(Math.floor(byteArray[36] / 16).toString()); + // Architecture type - if (byteArray[38] === 0) {hvsGrid = "OffGrid";} - if (byteArray[38] === 1) {hvsGrid = "OnGrid";} - if (byteArray[38] === 2) {hvsGrid = "Backup";} + if (byteArray[38] === 0) { + hvsGrid = 'OffGrid'; + } + if (byteArray[38] === 1) { + hvsGrid = 'OnGrid'; + } + if (byteArray[38] === 2) { + hvsGrid = 'Backup'; + } /* if ((ConfBatDetails) && (hvsModules > 2)) { adapter.log.error("Sorry, Details at the moment only for two modules. I need a wireshark dump from bigger systems to adjust the adapter."); ConfBatDetails = false; @@ -555,47 +818,52 @@ function decodePacket0(data) { } function decodePacket1(data) { - if(adapter.config.ConfStoreRawMessages) - adapter.setState("System.Raw_01", data.toString("hex"), true); + if (adapter.config.ConfStoreRawMessages) { + adapter.setState('System.Raw_01', data.toString('hex'), true); + } const byteArray = new Uint8Array(data); hvsSOC = buf2int16SI(byteArray, 3); - hvsMaxVolt = parseFloat((buf2int16SI(byteArray, 5) * 1.0 / 100.0).toFixed(2)); - hvsMinVolt = parseFloat((buf2int16SI(byteArray, 7) * 1.0 / 100.0).toFixed(2)); + hvsMaxVolt = parseFloat(((buf2int16SI(byteArray, 5) * 1.0) / 100.0).toFixed(2)); + hvsMinVolt = parseFloat(((buf2int16SI(byteArray, 7) * 1.0) / 100.0).toFixed(2)); hvsSOH = buf2int16SI(byteArray, 9); - hvsA = parseFloat((buf2int16SI(byteArray, 11) * 1.0 / 10.0).toFixed(1)); - hvsBattVolt = parseFloat((buf2int16US(byteArray, 13) * 1.0 / 100.0).toFixed(1)); + hvsA = parseFloat(((buf2int16SI(byteArray, 11) * 1.0) / 10.0).toFixed(1)); + hvsBattVolt = parseFloat(((buf2int16US(byteArray, 13) * 1.0) / 100.0).toFixed(1)); hvsMaxTemp = buf2int16SI(byteArray, 15); hvsMinTemp = buf2int16SI(byteArray, 17); hvsBatTemp = buf2int16SI(byteArray, 19); hvsError = buf2int16SI(byteArray, 29); - hvsParamT = byteArray[31].toString() + "." + byteArray[32].toString(); - hvsOutVolt = parseFloat((buf2int16US(byteArray, 35) * 1.0 / 100.0).toFixed(1)); - hvsPower = Math.round((hvsA * hvsOutVolt) * 100) / 100; + hvsParamT = `${byteArray[31].toString()}.${byteArray[32].toString()}`; + hvsOutVolt = parseFloat(((buf2int16US(byteArray, 35) * 1.0) / 100.0).toFixed(1)); + hvsPower = Math.round(hvsA * hvsOutVolt * 100) / 100; hvsDiffVolt = Math.round((hvsMaxVolt - hvsMinVolt) * 100) / 100; - hvsErrorString = ""; + hvsErrorString = ''; // hvsError = 65535; for (let j = 0; j < 16; j++) { if (((1 << j) & hvsError) !== 0) { if (hvsErrorString.length > 0) { - hvsErrorString += "; "; + hvsErrorString += '; '; } hvsErrorString += myErrors[j]; } } - if (hvsErrorString.length === 0) { hvsErrorString = "no Error"; } + if (hvsErrorString.length === 0) { + hvsErrorString = 'no Error'; + } hvsChargeTotal = buf2int32US(byteArray, 37) / 10; hvsDischargeTotal = buf2int32US(byteArray, 41) / 10; hvsETA = hvsDischargeTotal / hvsChargeTotal; } +// eslint-disable-next-line function decodePacketNOP(data) { - adapter.log.silly("Packet NOP"); + adapter.log.silly('Packet NOP'); } function decodePacket2(data) { - if(adapter.config.ConfStoreRawMessages) - adapter.setState("System.Raw_02", data.toString("hex"), true); + if (adapter.config.ConfStoreRawMessages) { + adapter.setState('System.Raw_02', data.toString('hex'), true); + } const byteArray = new Uint8Array(data); hvsBattType = byteArray[5]; hvsInvType = byteArray[3]; @@ -623,31 +891,34 @@ function decodePacket2(data) { //4 modules, 128 voltages, 48 temps } //leider hässlich dazugestrickt, wollte in die andere Logik nicht eingreifen - if (hvsBattType_fromSerial == "LVS") { - hvsBattType = "LVS"; + if (hvsBattType_fromSerial == 'LVS') { + hvsBattType = 'LVS'; hvsNumCells = hvsModules * 7; hvsNumTemps = 0; } - if (hvsBattType_fromSerial == "LVS") { //unterschiedliche WR-Tabelle je nach Batt-Typ + if (hvsBattType_fromSerial == 'LVS') { + //unterschiedliche WR-Tabelle je nach Batt-Typ hvsInvType_String = myINVsLVS[hvsInvType]; - } - else { + } else { hvsInvType_String = myINVs[hvsInvType]; } if (hvsInvType_String == undefined) { - hvsInvType_String = "undefined"; + hvsInvType_String = 'undefined'; } - if (hvsNumCells > 160) { hvsNumCells = 160; } - if (hvsNumTemps > 64) { hvsNumTemps = 64; } + if (hvsNumCells > 160) { + hvsNumCells = 160; + } + if (hvsNumTemps > 64) { + hvsNumTemps = 64; + } if (ConfBatDetails && FirstRun) { FirstRun = false; setObjectsCells(); } - adapter.log.silly ("NumCells: " + hvsNumCells +" Numtemps: " + hvsNumTemps + " Modules: " + hvsModules); + adapter.log.silly(`NumCells: ${hvsNumCells} Numtemps: ${hvsNumTemps} Modules: ${hvsModules}`); } - function decodePacket5(data, towerNumber = 0) { const byteArray = new Uint8Array(data); towerAttributes[towerNumber].hvsMaxmVolt = buf2int16SI(byteArray, 5); @@ -660,21 +931,22 @@ function decodePacket5(data, towerNumber = 0) { //starting with byte 101, ending with 131, Cell voltage 1-16 const MaxCells = 16; for (let i = 0; i < MaxCells; i++) { - adapter.log.silly("Battery Voltage-" + pad((i + 1), 3) + " :" + buf2int16SI(byteArray, i * 2 + 101)); + adapter.log.silly(`Battery Voltage-${pad(i + 1, 3)} :${buf2int16SI(byteArray, i * 2 + 101)}`); towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 1] = buf2int16SI(byteArray, i * 2 + 101); } // Balancing Flags // 17 bis 32 - towerAttributes[towerNumber].balancing = data.slice(17,33).toString("hex"); - towerAttributes[towerNumber].balancingcount = countSetBits (data.slice(17,33).toString("hex")); + towerAttributes[towerNumber].balancing = data.slice(17, 33).toString('hex'); + towerAttributes[towerNumber].balancingcount = countSetBits(data.slice(17, 33).toString('hex')); towerAttributes[towerNumber].chargeTotal = buf2int32US(byteArray, 33); towerAttributes[towerNumber].dischargeTotal = buf2int32US(byteArray, 37); - towerAttributes[towerNumber].eta = towerAttributes[towerNumber].dischargeTotal / towerAttributes[towerNumber].chargeTotal; + towerAttributes[towerNumber].eta = + towerAttributes[towerNumber].dischargeTotal / towerAttributes[towerNumber].chargeTotal; towerAttributes[towerNumber].batteryVolt = buf2int16SI(byteArray, 45); towerAttributes[towerNumber].outVolt = buf2int16SI(byteArray, 51); - towerAttributes[towerNumber].hvsSOCDiagnosis = parseFloat((buf2int16SI(byteArray, 53) * 1.0 / 10.0).toFixed(1)); + towerAttributes[towerNumber].hvsSOCDiagnosis = parseFloat(((buf2int16SI(byteArray, 53) * 1.0) / 10.0).toFixed(1)); towerAttributes[towerNumber].soh = parseFloat((buf2int16SI(byteArray, 55) * 1.0).toFixed(1)); towerAttributes[towerNumber].state = byteArray[59].toString(16) + byteArray[60].toString(16); } @@ -685,9 +957,11 @@ function decodePacket6(data, towerNumber = 0) { // first Voltage in byte 5+6 // Count = 80-17 --> 63 let MaxCells = hvsNumCells - 16; //0 to n-1 is the same like 1 to n - if (MaxCells > 64) { MaxCells = 64; } + if (MaxCells > 64) { + MaxCells = 64; + } for (let i = 0; i < MaxCells; i++) { - adapter.log.silly("Battery Voltage-" + pad((i + 17), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5)); + adapter.log.silly(`Battery Voltage-${pad(i + 17, 3)} :${buf2int16SI(byteArray, i * 2 + 5)}`); towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 17] = buf2int16SI(byteArray, i * 2 + 5); } } @@ -701,18 +975,22 @@ function decodePacket7(data, towerNumber = 0) { // first Voltage in byte 5+6 // Count = 128-80 --> 48 let MaxCells = hvsNumCells - 80; //0 to n-1 is the same like 1 to n - if (MaxCells > 48) { MaxCells = 48; } - adapter.log.silly("hvsModules =" + hvsModules + " maxCells= " + MaxCells); + if (MaxCells > 48) { + MaxCells = 48; + } + adapter.log.silly(`hvsModules =${hvsModules} maxCells= ${MaxCells}`); for (let i = 0; i < MaxCells; i++) { - adapter.log.silly("Battery Voltage-" + pad((i + 81), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5)); + adapter.log.silly(`Battery Voltage-${pad(i + 81, 3)} :${buf2int16SI(byteArray, i * 2 + 5)}`); towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 81] = buf2int16SI(byteArray, i * 2 + 5); } let MaxTemps = hvsNumTemps - 0; //0 to n-1 is the same like 1 to n - if (MaxTemps > 30) { MaxTemps = 30; } - adapter.log.silly("hvsModules =" + hvsModules + " MaxTemps= " + MaxTemps); + if (MaxTemps > 30) { + MaxTemps = 30; + } + adapter.log.silly(`hvsModules =${hvsModules} MaxTemps= ${MaxTemps}`); for (let i = 0; i < MaxTemps; i++) { - adapter.log.silly("Battery Temp " + pad(i + 1, 3) + " :" + byteArray[i + 103]); + adapter.log.silly(`Battery Temp ${pad(i + 1, 3)} :${byteArray[i + 103]}`); towerAttributes[towerNumber].hvsBatteryTempperCell[i + 1] = byteArray[i + 103]; } } @@ -720,10 +998,12 @@ function decodePacket7(data, towerNumber = 0) { function decodePacket8(data, towerNumber = 0) { const byteArray = new Uint8Array(data); let MaxTemps = hvsNumTemps - 30; //0 to n-1 is the same like 1 to n - if (MaxTemps > 34) { MaxTemps = 34; } - adapter.log.silly("hvsModules =" + hvsModules + " MaxTemps= " + MaxTemps); + if (MaxTemps > 34) { + MaxTemps = 34; + } + adapter.log.silly(`hvsModules =${hvsModules} MaxTemps= ${MaxTemps}`); for (let i = 0; i < MaxTemps; i++) { - adapter.log.silly("Battery Temp " + pad(i + 31, 3) + " :" + byteArray[i + 5]); + adapter.log.silly(`Battery Temp ${pad(i + 31, 3)} :${byteArray[i + 5]}`); towerAttributes[towerNumber].hvsBatteryTempperCell[i + 31] = byteArray[i + 5]; } } @@ -737,12 +1017,12 @@ function decodeResponse12(data, towerNumber = 0) { //starting with byte 101, ending with 131, Cell voltage 129-144 // Balancing Flags - towerAttributes[towerNumber].balancing = data.slice(17,33).toString("hex"); - towerAttributes[towerNumber].balancingcount = countSetBits (data.slice(17,33).toString("hex")); + towerAttributes[towerNumber].balancing = data.slice(17, 33).toString('hex'); + towerAttributes[towerNumber].balancingcount = countSetBits(data.slice(17, 33).toString('hex')); const MaxCells = 16; for (let i = 0; i < MaxCells; i++) { - adapter.log.silly("Battery Voltage-" + pad((i + 1 + 128), 3) + " :" + buf2int16SI(byteArray, i * 2 + 101)); + adapter.log.silly(`Battery Voltage-${pad(i + 1 + 128, 3)} :${buf2int16SI(byteArray, i * 2 + 101)}`); towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 1 + 128] = buf2int16SI(byteArray, i * 2 + 101); } } @@ -754,9 +1034,11 @@ function decodeResponse12(data, towerNumber = 0) { function decodeResponse13(data, towerNumber = 0) { const byteArray = new Uint8Array(data); let MaxCells = hvsNumCells - 128 - 16; // The first round measured up to 128 cells, request[12] then get another 16 - if (MaxCells > 16) { MaxCells = 16; } // With 5 HVS Modules, only 16 cells are remaining + if (MaxCells > 16) { + MaxCells = 16; + } // With 5 HVS Modules, only 16 cells are remaining for (let i = 0; i < MaxCells; i++) { - adapter.log.silly("Battery Voltage-" + pad((i + 1 + 16 + 128), 3) + " :" + buf2int16SI(byteArray, i * 2 + 5)); + adapter.log.silly(`Battery Voltage-${pad(i + 1 + 16 + 128, 3)} :${buf2int16SI(byteArray, i * 2 + 5)}`); towerAttributes[towerNumber].hvsBatteryVoltsperCell[i + 1 + 16 + 128] = buf2int16SI(byteArray, i * 2 + 5); } } @@ -764,17 +1046,17 @@ function decodeResponse13(data, towerNumber = 0) { function setConnected(adapter, isConnected) { if (adapter._connected !== isConnected) { adapter._connected = isConnected; - adapter.setState("info.connection", adapter._connected, true, err => + adapter.setState('info.connection', adapter._connected, true, err => // analyse if the state could be set (because of permissions) - err ? adapter.log.error("Can not update adapter._connected state: " + err) : - adapter.log.debug("connected set to " + adapter._connected)); + err + ? adapter.log.error(`Can not update adapter._connected state: ${err}`) + : adapter.log.debug(`connected set to ${adapter._connected}`), + ); } } - function setStates() { - - let ObjTowerString = ""; + let ObjTowerString = ''; adapter.log.silly(`hvsSerial >${hvsSerial}< hvsBMU >${hvsBMU}<; @@ -801,140 +1083,204 @@ hvsErrorStr >${hvsErrorString}<, BattType >${hvsBattType_fromSerial}<, Invert. Type >${hvsInvType_String}, Nr: ${hvsInvType}<`); - adapter.setState("System.Serial", hvsSerial, true); - adapter.setState("System.BMU", hvsBMU, true); - adapter.setState("System.BMUBankA", hvsBMUA, true); - adapter.setState("System.BMUBankB", hvsBMUB, true); - adapter.setState("System.BMS", hvsBMS, true); - adapter.setState("System.Modules", hvsModules, true); - adapter.setState("System.Towers", hvsTowers, true); - adapter.setState("System.Grid", hvsGrid, true); - adapter.setState("State.SOC", hvsSOC, true); - adapter.setState("State.VoltMax", hvsMaxVolt, true); - adapter.setState("State.VoltMin", hvsMinVolt, true); - adapter.setState("State.SOH", hvsSOH, true); - adapter.setState("State.Current", hvsA, true); - adapter.setState("State.VoltBatt", hvsBattVolt, true); - adapter.setState("State.TempMax", hvsMaxTemp, true); - adapter.setState("State.TempMin", hvsMinTemp, true); - adapter.setState("State.VoltDiff", hvsDiffVolt, true); - adapter.setState("State.Power", hvsPower, true /*ack*/); - adapter.setState("System.ParamT", hvsParamT, true); - adapter.setState("State.TempBatt", hvsBatTemp, true); - adapter.setState("State.VoltOut", hvsOutVolt, true); - adapter.setState("System.ErrorNum", hvsError, true); - adapter.setState("System.ErrorStr", hvsErrorString, true); + adapter.setState('System.Serial', hvsSerial, true); + adapter.setState('System.BMU', hvsBMU, true); + adapter.setState('System.BMUBankA', hvsBMUA, true); + adapter.setState('System.BMUBankB', hvsBMUB, true); + adapter.setState('System.BMS', hvsBMS, true); + adapter.setState('System.Modules', hvsModules, true); + adapter.setState('System.Towers', hvsTowers, true); + adapter.setState('System.Grid', hvsGrid, true); + adapter.setState('State.SOC', hvsSOC, true); + adapter.setState('State.VoltMax', hvsMaxVolt, true); + adapter.setState('State.VoltMin', hvsMinVolt, true); + adapter.setState('State.SOH', hvsSOH, true); + adapter.setState('State.Current', hvsA, true); + adapter.setState('State.VoltBatt', hvsBattVolt, true); + adapter.setState('State.TempMax', hvsMaxTemp, true); + adapter.setState('State.TempMin', hvsMinTemp, true); + adapter.setState('State.VoltDiff', hvsDiffVolt, true); + adapter.setState('State.Power', hvsPower, true /*ack*/); + adapter.setState('System.ParamT', hvsParamT, true); + adapter.setState('State.TempBatt', hvsBatTemp, true); + adapter.setState('State.VoltOut', hvsOutVolt, true); + adapter.setState('System.ErrorNum', hvsError, true); + adapter.setState('System.ErrorStr', hvsErrorString, true); if (hvsPower >= 0) { - adapter.setState("State.Power_Consumption", hvsPower, true); - adapter.setState("State.Power_Delivery", 0, true); + adapter.setState('State.Power_Consumption', hvsPower, true); + adapter.setState('State.Power_Delivery', 0, true); } else { - adapter.setState("State.Power_Consumption", 0, true); - adapter.setState("State.Power_Delivery", -hvsPower, true); + adapter.setState('State.Power_Consumption', 0, true); + adapter.setState('State.Power_Delivery', -hvsPower, true); } - adapter.setState("System.BattType", hvsBattType_fromSerial, true); - adapter.setState("System.InvType", hvsInvType_String, true); - adapter.setState("System.ChargeTotal", hvsChargeTotal, true); - adapter.setState("System.DischargeTotal", hvsDischargeTotal, true); - adapter.setState("System.ETA", hvsETA, true); + adapter.setState('System.BattType', hvsBattType_fromSerial, true); + adapter.setState('System.InvType', hvsInvType_String, true); + adapter.setState('System.ChargeTotal', hvsChargeTotal, true); + adapter.setState('System.DischargeTotal', hvsDischargeTotal, true); + adapter.setState('System.ETA', hvsETA, true); if (myNumberforDetails == 0) { // For every tower - adapter.log.silly("Tower attributes: " + JSON.stringify(towerAttributes)); - for(let t = 0; t < towerAttributes.length; t++) { + adapter.log.silly(`Tower attributes: ${JSON.stringify(towerAttributes)}`); + for (let t = 0; t < towerAttributes.length; t++) { try { if (ConfBydTowerCount > 1) { - ObjTowerString = ".Tower_" +(t + 1); + ObjTowerString = `.Tower_${t + 1}`; } // Test if all required msg received. - if(towerAttributes[t].hvsMaxmVolt) { - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltMax`, towerAttributes[t].hvsMaxmVolt, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltMin`, towerAttributes[t].hvsMinmVolt, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltMaxCell`, towerAttributes[t].hvsMaxmVoltCell, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltMinCell`, towerAttributes[t].hvsMinmVoltCell, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.TempMaxCell`, towerAttributes[t].hvsMaxTempCell, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.TempMinCell`, towerAttributes[t].hvsMinTempCell, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.ChargeTotal`, towerAttributes[t].chargeTotal, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.DischargeTotal`, towerAttributes[t].dischargeTotal, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.ETA`, towerAttributes[t].eta, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.BatteryVolt`, towerAttributes[t].batteryVolt, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.OutVolt`, towerAttributes[t].outVolt, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.SOC`, towerAttributes[t].hvsSOCDiagnosis, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.SOH`, towerAttributes[t].soh, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.State`, towerAttributes[t].state, true); - adapter.log.debug(`Tower_${t+1} balancing >${towerAttributes[t].balancing}<`); - adapter.log.debug(`Tower_${t+1} balcount >${towerAttributes[t].balancingcount}<`); + if (towerAttributes[t].hvsMaxmVolt) { + adapter.setState(`Diagnosis${ObjTowerString}.mVoltMax`, towerAttributes[t].hvsMaxmVolt, true); + adapter.setState(`Diagnosis${ObjTowerString}.mVoltMin`, towerAttributes[t].hvsMinmVolt, true); + adapter.setState( + `Diagnosis${ObjTowerString}.mVoltMaxCell`, + towerAttributes[t].hvsMaxmVoltCell, + true, + ); + adapter.setState( + `Diagnosis${ObjTowerString}.mVoltMinCell`, + towerAttributes[t].hvsMinmVoltCell, + true, + ); + adapter.setState(`Diagnosis${ObjTowerString}.TempMaxCell`, towerAttributes[t].hvsMaxTempCell, true); + adapter.setState(`Diagnosis${ObjTowerString}.TempMinCell`, towerAttributes[t].hvsMinTempCell, true); + adapter.setState(`Diagnosis${ObjTowerString}.ChargeTotal`, towerAttributes[t].chargeTotal, true); + adapter.setState( + `Diagnosis${ObjTowerString}.DischargeTotal`, + towerAttributes[t].dischargeTotal, + true, + ); + adapter.setState(`Diagnosis${ObjTowerString}.ETA`, towerAttributes[t].eta, true); + adapter.setState(`Diagnosis${ObjTowerString}.BatteryVolt`, towerAttributes[t].batteryVolt, true); + adapter.setState(`Diagnosis${ObjTowerString}.OutVolt`, towerAttributes[t].outVolt, true); + adapter.setState(`Diagnosis${ObjTowerString}.SOC`, towerAttributes[t].hvsSOCDiagnosis, true); + adapter.setState(`Diagnosis${ObjTowerString}.SOH`, towerAttributes[t].soh, true); + adapter.setState(`Diagnosis${ObjTowerString}.State`, towerAttributes[t].state, true); + adapter.log.debug(`Tower_${t + 1} balancing >${towerAttributes[t].balancing}<`); + adapter.log.debug(`Tower_${t + 1} balcount >${towerAttributes[t].balancingcount}<`); if (t == 0) { - - adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingOne`, towerAttributes[t].balancing ? towerAttributes[t].balancing : "", true); - adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingCountOne`, towerAttributes[t].balancingcount, true); + adapter.setState( + `Diagnosis${ObjTowerString}.BalancingOne`, + towerAttributes[t].balancing ? towerAttributes[t].balancing : '', + true, + ); + adapter.setState( + `Diagnosis${ObjTowerString}.BalancingCountOne`, + towerAttributes[t].balancingcount, + true, + ); } else { - adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingTwo`, towerAttributes[t].balancing ? towerAttributes[t].balancing : "", true); - adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingCountTwo`, towerAttributes[t].balancingcount, true ); + adapter.setState( + `Diagnosis${ObjTowerString}.BalancingTwo`, + towerAttributes[t].balancing ? towerAttributes[t].balancing : '', + true, + ); + adapter.setState( + `Diagnosis${ObjTowerString}.BalancingCountTwo`, + towerAttributes[t].balancingcount, + true, + ); } -/* + /* if (towerAttributes[t].balancing) adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingOne`, towerAttributes[t].balancing_one, true); if (towerAttributes[t].balancingcount_one) adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingOne`, towerAttributes[t].balancing_one, true); adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingTwo`, towerAttributes[t].balancing_two ? towerAttributes[t].balancing_two : "", true); adapter.setState(`Diagnosis` + ObjTowerString + `.BalancingCountTwo`, towerAttributes[t].balancingcount_two ? towerAttributes[t].balancingcount_two : 0, true ); */ for (let i = 1; i <= hvsNumCells; i++) { - adapter.setState(`CellDetails` + ObjTowerString + `.CellVolt` + pad(i, 3), towerAttributes[t].hvsBatteryVoltsperCell[i] ? towerAttributes[t].hvsBatteryVoltsperCell[i] : 0 , true); + adapter.setState( + `CellDetails${ObjTowerString}.CellVolt${pad(i, 3)}`, + towerAttributes[t].hvsBatteryVoltsperCell[i] + ? towerAttributes[t].hvsBatteryVoltsperCell[i] + : 0, + true, + ); } - const mVoltDefDeviation = stabw(towerAttributes[t].hvsBatteryVoltsperCell.filter((v) => v > 0)); - const mVoltMean = mean(towerAttributes[t].hvsBatteryVoltsperCell.filter((v) => v > 0)); - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltDefDeviation`, mVoltDefDeviation,true); - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltMean`, mVoltMean, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltGt150DefVar`, towerAttributes[t].hvsBatteryVoltsperCell.filter((v) => v > (mVoltMean + (mVoltDefDeviation * 1.5))).length, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.mVoltLt150DefVar`, towerAttributes[t].hvsBatteryVoltsperCell.filter((v) => v > 0).filter((v) => v < (mVoltMean - (mVoltDefDeviation * 1.5))).length, true); + const mVoltDefDeviation = stabw(towerAttributes[t].hvsBatteryVoltsperCell.filter(v => v > 0)); + const mVoltMean = mean(towerAttributes[t].hvsBatteryVoltsperCell.filter(v => v > 0)); + adapter.setState(`Diagnosis${ObjTowerString}.mVoltDefDeviation`, mVoltDefDeviation, true); + adapter.setState(`Diagnosis${ObjTowerString}.mVoltMean`, mVoltMean, true); + adapter.setState( + `Diagnosis${ObjTowerString}.mVoltGt150DefVar`, + towerAttributes[t].hvsBatteryVoltsperCell.filter(v => v > mVoltMean + mVoltDefDeviation * 1.5) + .length, + true, + ); + adapter.setState( + `Diagnosis${ObjTowerString}.mVoltLt150DefVar`, + towerAttributes[t].hvsBatteryVoltsperCell + .filter(v => v > 0) + .filter(v => v < mVoltMean - mVoltDefDeviation * 1.5).length, + true, + ); for (let i = 1; i <= hvsNumTemps; i++) { - adapter.setState(`CellDetails` + ObjTowerString + `.CellTemp` + pad(i, 3), towerAttributes[t].hvsBatteryTempperCell[i] ? towerAttributes[t].hvsBatteryTempperCell[i] : 0, true); + adapter.setState( + `CellDetails${ObjTowerString}.CellTemp${pad(i, 3)}`, + towerAttributes[t].hvsBatteryTempperCell[i] + ? towerAttributes[t].hvsBatteryTempperCell[i] + : 0, + true, + ); } - const tempDefDeviation = stabw(towerAttributes[t].hvsBatteryTempperCell.filter((v) => v > 0)); - const tempMean = mean(towerAttributes[t].hvsBatteryTempperCell.filter((v) => v > 0)); - adapter.setState(`Diagnosis` + ObjTowerString + `.TempDefDeviation`, tempDefDeviation,true); - adapter.setState(`Diagnosis` + ObjTowerString + `.TempMean`, tempMean, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.TempGt150DefVar`, towerAttributes[t].hvsBatteryTempperCell.filter((v) => v > (tempMean + (tempDefDeviation * 1.5))).length, true); - adapter.setState(`Diagnosis` + ObjTowerString + `.TempLt150DefVar`, towerAttributes[t].hvsBatteryTempperCell.filter((v) => v > 0).filter((v) => v < (tempMean - (tempDefDeviation * 1.5))).length, true); - - adapter.log.silly(`Tower_${t+1} hvsMaxmVolt >${towerAttributes[t].hvsMaxmVolt}<`); - adapter.log.silly(`Tower_${t+1} hvsMinmVolt >${towerAttributes[t].hvsMinmVolt}<`); - adapter.log.silly(`Tower_${t+1} hvsMaxmVoltCell >${towerAttributes[t].hvsMaxmVoltCell}<`); - adapter.log.silly(`Tower_${t+1} hvsMinmVoltCell >${towerAttributes[t].hvsMinmVoltCell}<`); - adapter.log.silly(`Tower_${t+1} hvsMaxTempCell >${towerAttributes[t].hvsMaxTempCell}<`); - adapter.log.silly(`Tower_${t+1} hvsMinTempCell >${towerAttributes[t].hvsMinTempCell}<`); - adapter.log.silly(`Tower_${t+1} hvsSOC (Diag) >${towerAttributes[t].hvsSOCDiagnosis}<`); + const tempDefDeviation = stabw(towerAttributes[t].hvsBatteryTempperCell.filter(v => v > 0)); + const tempMean = mean(towerAttributes[t].hvsBatteryTempperCell.filter(v => v > 0)); + adapter.setState(`Diagnosis${ObjTowerString}.TempDefDeviation`, tempDefDeviation, true); + adapter.setState(`Diagnosis${ObjTowerString}.TempMean`, tempMean, true); + adapter.setState( + `Diagnosis${ObjTowerString}.TempGt150DefVar`, + towerAttributes[t].hvsBatteryTempperCell.filter(v => v > tempMean + tempDefDeviation * 1.5) + .length, + true, + ); + adapter.setState( + `Diagnosis${ObjTowerString}.TempLt150DefVar`, + towerAttributes[t].hvsBatteryTempperCell + .filter(v => v > 0) + .filter(v => v < tempMean - tempDefDeviation * 1.5).length, + true, + ); + + adapter.log.silly(`Tower_${t + 1} hvsMaxmVolt >${towerAttributes[t].hvsMaxmVolt}<`); + adapter.log.silly(`Tower_${t + 1} hvsMinmVolt >${towerAttributes[t].hvsMinmVolt}<`); + adapter.log.silly(`Tower_${t + 1} hvsMaxmVoltCell >${towerAttributes[t].hvsMaxmVoltCell}<`); + adapter.log.silly(`Tower_${t + 1} hvsMinmVoltCell >${towerAttributes[t].hvsMinmVoltCell}<`); + adapter.log.silly(`Tower_${t + 1} hvsMaxTempCell >${towerAttributes[t].hvsMaxTempCell}<`); + adapter.log.silly(`Tower_${t + 1} hvsMinTempCell >${towerAttributes[t].hvsMinTempCell}<`); + adapter.log.silly(`Tower_${t + 1} hvsSOC (Diag) >${towerAttributes[t].hvsSOCDiagnosis}<`); } - } catch(err) { - adapter.log.error(`Cant read in Tower ${t} with ${err.message}` ); + } catch (err) { + adapter.log.error( + `Cant read in Tower ${t} with ${err instanceof Error ? err.message : 'unknown error'}`, + ); } } } - } function startPoll(adapter) { //erster Start sofort (500ms), dann entsprechend der Config - dann muss man nicht beim Entwickeln warten bis der erste Timer durch ist. FirstRun = true; - idTimeout1 = setTimeout(() => { Poll(adapter); }, 500); + idTimeout1 = setTimeout(() => { + Poll(adapter); + }, 500); idInterval1 = setInterval(() => Poll(adapter), confBatPollTime * 1000); - adapter.log.info("gestartet: " + adapter.config.ConfPollInterval + " " + idInterval1); + adapter.log.info(`gestartet: ${adapter.config.ConfPollInterval} ${idInterval1}`); } function stopPoll() { idInterval1 && clearInterval(idInterval1); } -IPClient.on("data", function (data) { - adapter.log.silly("Received, State: " + myState + ", Data: " + data.toString("hex")); +IPClient.on('data', function (data) { + adapter.log.silly(`Received, State: ${myState}, Data: ${data.toString('hex')}`); /* if (ConfTestMode) { const PacketNumber = myState - 1; adapter.log.info("Received, Packet: " + PacketNumber + " Data: " + data.toString("hex")); } */ if (checkPacket(data) == false) { - adapter.log.error("error: no valid data"); + adapter.log.error('error: no valid data'); IPClient.destroy(); setConnected(adapter, false); myState = 0; @@ -961,7 +1307,7 @@ IPClient.on("data", function (data) { break; case 4: //test if it is time for reading all data. If not stop here decodePacket2(data); - if ((myNumberforDetails < ConfBatDetailshowoften) || (ConfBatDetails == false)) { + if (myNumberforDetails < ConfBatDetailshowoften || ConfBatDetails == false) { setStates(); IPClient.destroy(); myState = 0; @@ -1025,7 +1371,7 @@ IPClient.on("data", function (data) { IPClient.write(myRequests[9]); // Switch to second turn for the last module }, 200); } else { - if(ConfBydTowerCount > 1 ) { + if (ConfBydTowerCount > 1) { myState = 16; IPClient.setTimeout(1000); setTimeout(() => { @@ -1049,7 +1395,7 @@ IPClient.on("data", function (data) { case 12: decodePacketNOP(data); IPClient.setTimeout(8000); - adapter.log.silly("waiting 3 seconds to measure cells"); + adapter.log.silly('waiting 3 seconds to measure cells'); setTimeout(() => { myState = 13; IPClient.write(myRequests[11]); @@ -1072,8 +1418,8 @@ IPClient.on("data", function (data) { break; case 15: decodeResponse13(data); - if(ConfBydTowerCount > 1 ) { - adapter.log.silly("Start to read Tower 2"); + if (ConfBydTowerCount > 1) { + adapter.log.silly('Start to read Tower 2'); myState = 16; IPClient.setTimeout(1000); setTimeout(() => { @@ -1139,32 +1485,32 @@ IPClient.on("data", function (data) { } }); - -IPClient.on("timeout", function () { +IPClient.on('timeout', function () { IPClient.destroy(); setConnected(adapter, false); adapter.log.error(`no connection in state ${myState} to IP: ${adapter.config.ConfIPAdress}`); myState = 0; }); -IPClient.on("error", function () { +IPClient.on('error', function () { IPClient.destroy(); setConnected(adapter, false); myState = 0; - adapter.log.error("Error connecting to " + adapter.config.ConfIPAdress); + adapter.log.error(`Error connecting to ${adapter.config.ConfIPAdress}`); }); - -function Poll(adapter) { - if (myState > 0) return; +function Poll(adapter) { + if (myState > 0) { + return; + } myState = 1; IPClient.setTimeout(1000); myNumberforDetails += 1; - adapter.log.silly("myNumberforDetails:" + myNumberforDetails); - adapter.log.silly("Poll start, IP:" + adapter.config.ConfIPAdress); + adapter.log.silly(`myNumberforDetails:${myNumberforDetails}`); + adapter.log.silly(`Poll start, IP:${adapter.config.ConfIPAdress}`); // Erstelle die Arrays - for(let towerNumber = 0; towerNumber < ConfBydTowerCount; towerNumber++) { - adapter.log.silly("Empty tower " + towerNumber); + for (let towerNumber = 0; towerNumber < ConfBydTowerCount; towerNumber++) { + adapter.log.silly(`Empty tower ${towerNumber}`); towerAttributes[towerNumber] = {}; towerAttributes[towerNumber].hvsBatteryVoltsperCell = []; towerAttributes[towerNumber].hvsBatteryTempperCell = []; @@ -1177,7 +1523,6 @@ function Poll(adapter) { } async function main() { - // Reset the connection indicator during startup // await this.setStateAsync("info.connection", false, true); setConnected(adapter, false); @@ -1186,29 +1531,29 @@ async function main() { // The adapters config (in the instance object everything under the attribute "native") is accessible via // adapter.config: - adapter.log.info("Poll Interval: " + adapter.config.ConfPollInterval); + adapter.log.info(`Poll Interval: ${adapter.config.ConfPollInterval}`); confBatPollTime = parseInt(adapter.config.ConfPollInterval); if (confBatPollTime < 3) { //confBatPollTime = 60; - adapter.log.warn("poll to often - recommendation is not more than every 3 seconds"); + adapter.log.warn('poll to often - recommendation is not more than every 3 seconds'); } ConfBydTowerCount = adapter.config.ConfBydTowerCount ? adapter.config.ConfBydTowerCount : 1; - adapter.log.info("BYD IP Adress: " + adapter.config.ConfIPAdress); - ConfBatDetails = (adapter.config.ConfBatDetails ? true : false); - adapter.log.info("Bat Details : " + adapter.config.ConfBatDetails); + adapter.log.info(`BYD IP Adress: ${adapter.config.ConfIPAdress}`); + ConfBatDetails = adapter.config.ConfBatDetails ? true : false; + adapter.log.info(`Bat Details : ${adapter.config.ConfBatDetails}`); ConfBatDetailshowoften = parseInt(adapter.config.ConfDetailshowoften); - adapter.log.info("Tower count: " + adapter.config.ConfBydTowerCount); + adapter.log.info(`Tower count: ${adapter.config.ConfBydTowerCount}`); /*if (ConfBatDetailshowoften < 10) { ConfBatDetails = false; adapter.log.error("Details polling to often - disabling "); }*/ - ConfTestMode = (adapter.config.ConfTestMode ? true : false); - adapter.log.info("BatDetailshowoften: " + ConfBatDetailshowoften); - adapter.log.silly("TestMode= " + ConfTestMode); + ConfTestMode = adapter.config.ConfTestMode ? true : false; + adapter.log.info(`BatDetailshowoften: ${ConfBatDetailshowoften}`); + adapter.log.silly(`TestMode= ${ConfTestMode}`); myNumberforDetails = ConfBatDetailshowoften; // adapter.config.ConfPollInterval = parseInt(adapter.config.ConfPollInterval, 10) || 60; - adapter.log.info("starte poll"); + adapter.log.info('starte poll'); startPoll(adapter); // examples for the checkPassword/checkGroup functions @@ -1223,13 +1568,17 @@ async function main() { * Calculate default deviation / Standardabweichung */ const stabw = function (array) { - let len =0; - const sum = array.reduce(function (pv, cv) { ++len; return pv+cv;}, 0); + let len = 0; + const sum = array.reduce(function (pv, cv) { + ++len; + return pv + cv; + }, 0); const mean = sum / len; let result = 0; - for(let i = 0; i a + b, 0); - return (sum / array.length) || 0; + return sum / array.length || 0; }; -// @ts-ignore parent is a valid property on module -if (module.parent) { - // Export startAdapter in compact mode +if (require.main !== module) { module.exports = startAdapter; } else { - // otherwise start the instance directly startAdapter(); } - function countSetBits(hexString) { // Hexadezimale Zeichen in einen Binärstring umwandeln let binaryString = ''; @@ -1258,7 +1603,7 @@ function countSetBits(hexString) { // Jeder Hex-Char in einen Binär-String umwandeln und auf 4 Stellen auffüllen binaryString += parseInt(hexString[i], 16).toString(2).padStart(4, '0'); } - + // Anzahl der '1' Bits im Binärstring zählen let setBitsCount = 0; for (let i = 0; i < binaryString.length; i++) { @@ -1266,6 +1611,6 @@ function countSetBits(hexString) { setBitsCount++; } } - + return setBitsCount; -} \ No newline at end of file +}